Annotation of libaitio/src/aitio.c, revision 1.5.4.1

1.1       misho       1: /*************************************************************************
1.5       misho       2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
                      3: *  by Michael Pounov <misho@elwix.org>
1.1       misho       4: *
                      5: * $Author: misho $
1.5.4.1 ! misho       6: * $Id: aitio.c,v 1.5 2011/04/20 22:56:32 misho Exp $
1.1       misho       7: *
1.5       misho       8: **************************************************************************
                      9: The ELWIX and AITNET software is distributed under the following
                     10: terms:
                     11: 
                     12: All of the documentation and software included in the ELWIX and AITNET
                     13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
                     14: 
                     15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
                     16:        by Michael Pounov <misho@elwix.org>.  All rights reserved.
                     17: 
                     18: Redistribution and use in source and binary forms, with or without
                     19: modification, are permitted provided that the following conditions
                     20: are met:
                     21: 1. Redistributions of source code must retain the above copyright
                     22:    notice, this list of conditions and the following disclaimer.
                     23: 2. Redistributions in binary form must reproduce the above copyright
                     24:    notice, this list of conditions and the following disclaimer in the
                     25:    documentation and/or other materials provided with the distribution.
                     26: 3. All advertising materials mentioning features or use of this software
                     27:    must display the following acknowledgement:
                     28: This product includes software developed by Michael Pounov <misho@elwix.org>
                     29: ELWIX - Embedded LightWeight unIX and its contributors.
                     30: 4. Neither the name of AITNET nor the names of its contributors
                     31:    may be used to endorse or promote products derived from this software
                     32:    without specific prior written permission.
                     33: 
                     34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
                     35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     44: SUCH DAMAGE.
                     45: */
1.1       misho      46: #include "global.h"
                     47: 
                     48: 
1.2       misho      49: int io_Debug;
                     50: 
                     51: 
1.1       misho      52: #pragma GCC visibility push(hidden)
                     53: 
                     54: int io_Errno;
                     55: char io_Error[STRSIZ];
                     56: 
                     57: #pragma GCC visibility pop
                     58: 
                     59: 
                     60: // io_GetErrno() Get error code of last operation
1.5.4.1 ! misho      61: inline int
        !            62: io_GetErrno()
1.1       misho      63: {
                     64:        return io_Errno;
                     65: }
                     66: 
                     67: // io_GetError() Get error text of last operation
1.5.4.1 ! misho      68: inline const char *
        !            69: io_GetError()
1.1       misho      70: {
                     71:        return io_Error;
                     72: }
                     73: 
                     74: // io_SetErr() Set error to variables for internal use!!!
1.5.4.1 ! misho      75: inline void
        !            76: io_SetErr(int eno, char *estr, ...)
1.1       misho      77: {
                     78:        va_list lst;
                     79: 
                     80:        io_Errno = eno;
                     81:        memset(io_Error, 0, STRSIZ);
                     82:        va_start(lst, estr);
                     83:        vsnprintf(io_Error, STRSIZ, estr, lst);
                     84:        va_end(lst);
                     85: }
                     86: 
                     87: 
                     88: /*
                     89:  * ioPromptRead() Read data from input h[0] with prompt to output h[1]
                     90:  * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
                     91:  * @csPrompt = Prompt before input, may be NULL
                     92:  * @psData = Readed data
                     93:  * @dataLen = Length of data
                     94:  * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
                     95: */
1.5.4.1 ! misho      96: int
        !            97: ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen)
1.1       misho      98: {
                     99:        int ok = 0;
                    100:        FILE *inp, *out;
                    101:        char szLine[BUFSIZ], *pos;
                    102: 
                    103:        if (!psData || !dataLen)
                    104:                return -1;
                    105: 
                    106:        inp = fdopen(!h ? 0 : h[0], "r");
                    107:        if (!inp) {
                    108:                LOGERR;
                    109:                return -1;
                    110:        }
                    111:        out = fdopen(!h ? 1 : h[1], "w");
                    112:        if (!out) {
                    113:                LOGERR;
                    114:                return -1;
                    115:        }
                    116: 
                    117:        while (!ok) {
                    118:                if (csPrompt) {
                    119:                        fprintf(out, "%s", csPrompt);
                    120:                        fflush(out);
                    121:                }
                    122: 
                    123:                memset(szLine, 0, BUFSIZ);
                    124:                if (!fgets(szLine, BUFSIZ, inp)) {
                    125:                        clearerr(inp);
                    126:                        fpurge(out);
                    127:                        fflush(out);
                    128:                        return 0;
                    129:                }
                    130: 
                    131:                if ((pos = strchr(szLine, '\n')))
                    132:                        *pos = 0;
                    133: 
                    134:                strlcpy(psData, szLine, dataLen);
                    135:                ok = 1;
                    136:        }
                    137: 
                    138:        return pos - szLine;
                    139: }
                    140: 
                    141: /*
                    142:  * ioPromptPassword() Read password from input h[0] with prompt to output h[1]
                    143:  * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
                    144:  * @csPrompt = Prompt before input, may be NULL
                    145:  * @psPass = Readed password
                    146:  * @passLen = Length of password
                    147:  * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation
                    148:  * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
                    149: */
1.5.4.1 ! misho     150: int
        !           151: ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm)
1.1       misho     152: {
                    153:        int ret, ok = 0;
                    154:        FILE *inp, *out;
                    155:        char szLine[2][STRSIZ];
                    156:        struct sgttyb tty_state;
                    157: 
                    158:        if (!psPass || !passLen)
                    159:                return -1;
                    160: 
                    161:        inp = fdopen(!h ? 0 : h[0], "r");
                    162:        if (!inp) {
                    163:                LOGERR;
                    164:                return -1;
                    165:        }
                    166:        out = fdopen(!h ? 1 : h[1], "w");
                    167:        if (!out) {
                    168:                LOGERR;
                    169:                return -1;
                    170:        }
                    171: 
                    172:        if (ioctl(fileno(inp), TIOCGETP, &tty_state) == -1) {
                    173:                LOGERR;
                    174:                return -1;
                    175:        } else {
                    176:                tty_state.sg_flags &= ~ECHO;
                    177:                if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
                    178:                        LOGERR;
                    179:                        return -1;
                    180:                }
                    181:        }
                    182: 
                    183:        while (!ok) {
                    184:                switch ((ret = ioPromptRead(h, (!csPrompt || !*csPrompt) ? "Password:" : csPrompt, 
                    185:                                                szLine[0], STRSIZ))) {
                    186:                        case -1:
                    187:                                LOGERR;
                    188:                                ok = -1;
                    189:                        case 0:
                    190:                                goto next;
                    191:                }
                    192:                if (confirm) {
                    193:                        fprintf(out, "\n");
                    194:                        fflush(out);
                    195: 
                    196:                        switch (ioPromptRead(h, "Password confirm:", szLine[1], STRSIZ)) {
                    197:                                case -1:
                    198:                                        LOGERR;
                    199:                                        ok = -1;
                    200:                                        goto next;
                    201:                                case 0:
                    202:                                default:
                    203:                                        if (strcmp(szLine[0], szLine[1])) {
                    204:                                                fprintf(out, "\n\07\07Mismatch - Try again!\n");
                    205:                                                fflush(out);
                    206:                                                continue;
                    207:                                        }
                    208:                        }
                    209:                }
                    210: 
                    211:                strlcpy(psPass, szLine[0], passLen);
                    212:                ok = ret;
                    213:                fprintf(out, "\n");
                    214:                fflush(out);
                    215:        }
                    216: 
                    217: next:
                    218:        tty_state.sg_flags |= ECHO;
                    219:        if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
                    220:                LOGERR;
                    221:                return -1;
                    222:        }
                    223: 
                    224:        return ok;
                    225: }
                    226: 
                    227: /*
                    228:  * ioRegexVerify() Function for verify data match in regex expression
                    229:  * @csRegex = Regulare expression pattern
                    230:  * @csData = Data for check and verify
                    231:  * @startPos = Return start positions
                    232:  * @endPos = Return end positions
                    233:  * return: NULL not match or error; !=NULL begin of matched data
                    234: */
1.5.4.1 ! misho     235: const char *
        !           236: ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos)
1.1       misho     237: {
                    238:        regex_t re;
                    239:        regmatch_t match;
                    240:        char szErr[STRSIZ];
                    241:        int ret, flg;
                    242:        const char *pos;
                    243: 
                    244:        if (!csRegex || !csData)
                    245:                return NULL;
                    246: 
                    247:        if ((ret = regcomp(&re, csRegex, REG_EXTENDED))) {
                    248:                regerror(ret, &re, szErr, STRSIZ);
                    249:                io_SetErr(ret, "Error:: %s\n", szErr);
                    250:                regfree(&re);
                    251:                return NULL;
                    252:        }
                    253: 
                    254:        for (ret = flg = 0, pos = csData; !(ret = regexec(&re, pos, 1, &match, flg)); 
                    255:                        pos += match.rm_eo, flg = REG_NOTBOL) {
                    256:                if (startPos)
                    257:                        *startPos = match.rm_so;
                    258:                if (endPos)
                    259:                        *endPos = match.rm_eo;
                    260: 
                    261:                pos += match.rm_so;
                    262:                break;
                    263:        }
                    264: 
                    265:        if (ret) {
                    266:                regerror(ret, &re, szErr, STRSIZ);
                    267:                io_SetErr(ret, "Error:: %s\n", szErr);
                    268:                pos = NULL;
                    269:        }
                    270: 
                    271:        regfree(&re);
                    272:        return pos;
                    273: }
                    274: 
                    275: /*
                    276:  * ioRegexGet() Function for get data match in regex expression
                    277:  * @csRegex = Regulare expression pattern
                    278:  * @csData = Data from get
                    279:  * @psString = Returned string if match
                    280:  * @strLen = Length of string
                    281:  * return: 0 not match; >0 count of returned chars
                    282: */
1.5.4.1 ! misho     283: int
        !           284: ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen)
1.1       misho     285: {
                    286:        int sp, ep, len;
                    287:        const char *str;
                    288: 
                    289:        if (!csRegex || !csData)
                    290:                return -1;
                    291: 
                    292:        str = ioRegexVerify(csRegex, csData, &sp, &ep);
                    293:        if (!str)
                    294:                return 0;
                    295: 
                    296:        len = ep - sp;
                    297:        if (psString && strLen) {
                    298:                memset(psString, 0, strLen);
                    299:                strncpy(psString, str, strLen <= len ? strLen - 1 : len);
                    300:        }
                    301: 
                    302:        return len;
                    303: }
                    304: 
                    305: /*
                    306:  * ioRegexReplace() Function for replace data match in regex expression with newdata
                    307:  * @csRegex = Regulare expression pattern
                    308:  * @csData = Source data
                    309:  * @csNew = Data for replace
                    310:  * return: NULL not match or error; !=NULL allocated new string, must be free after use!
                    311: */
1.5.4.1 ! misho     312: char *
        !           313: ioRegexReplace(const char *csRegex, const char *csData, const char *csNew)
1.1       misho     314: {
                    315:        int sp, ep, len;
                    316:        char *str = NULL;
                    317: 
                    318:        if (!csRegex || !csData)
                    319:                return NULL;
                    320: 
                    321:        if (!ioRegexVerify(csRegex, csData, &sp, &ep))
                    322:                return NULL;
                    323: 
                    324:        // ___ before match
                    325:        len = sp + 1;
                    326:        str = malloc(len);
                    327:        if (!str) {
                    328:                LOGERR;
                    329:                return NULL;
                    330:        } else
                    331:                strlcpy(str, csData, len);
                    332:        // * replace match *
                    333:        if (csNew) {
                    334:                len += strlen(csNew);
                    335:                str = realloc(str, len);
                    336:                if (!str) {
                    337:                        LOGERR;
                    338:                        return NULL;
                    339:                } else
                    340:                        strlcat(str, csNew, len);
                    341:        }
                    342:        // after match ___
                    343:        len += strlen(csData) - ep;
                    344:        str = realloc(str, len);
                    345:        if (!str) {
                    346:                LOGERR;
                    347:                return NULL;
                    348:        } else
                    349:                strlcat(str, csData + ep, len);
                    350: 
                    351:        return str;
                    352: }
1.2       misho     353: 
1.3       misho     354: /*
                    355:  * ioVarAst() Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}"
                    356:  * @csString = Input string
                    357:  * return: NULL error, !=NULL Allocated new string evaluated from input string, must be free()
                    358: */
                    359: char *
                    360: ioVarAst(const char *csString)
                    361: {
                    362:        char *ext, *str, *out = NULL;
                    363:        int e[2] = { 0 };
                    364: 
                    365:        if (!csString)
                    366:                return NULL;
                    367: 
                    368:        if (!strchr(csString, '{') || !strrchr(csString, '}')) {
                    369:                memset(io_Error, 0, STRSIZ);
                    370:                snprintf(io_Error, STRSIZ, "Error:: Invalid input string format ... "
                    371:                                "must be like {text[:[-]#[:#]]}");
                    372:                io_Errno = EINVAL;
                    373:                return NULL;
                    374:        } else {
                    375:                str = strdup(strchr(csString, '{') + 1);
                    376:                *strrchr(str, '}') = 0;
                    377:        }
                    378: 
                    379:        if ((ext = strchr(str, ':'))) {
                    380:                *ext++ = 0;
                    381:                e[0] = strtol(ext, NULL, 0);
                    382:                if ((ext = strchr(ext, ':')))
                    383:                        e[1] = strtol(++ext, NULL, 0);
                    384: 
                    385:                /* make cut prefix */
                    386:                if (e[0] >= 0)
                    387:                        ext = str + e[0];
                    388:                else
                    389:                        ext = str + strlen(str) + e[0];
                    390:                /* make cut suffix */
                    391:                if (e[1] > 0)
                    392:                        *(ext + e[1]) = 0;
                    393:        } else
                    394:                /* ok, clear show */
                    395:                ext = str;
                    396: 
                    397:        out = strdup(ext);
                    398:        free(str);
                    399: 
                    400:        return out;
                    401: }
                    402: 
1.2       misho     403: 
                    404: /*
                    405:  * ioMkDir() Function for racursive directory creation and validation
                    406:  * @csDir = Full directory path
                    407:  * @mode = Mode for directory creation if missing dir
                    408:  * return: -1 error, 0 directory path exist, >0 created missing dirs
                    409: */
                    410: int
                    411: ioMkDir(const char *csDir, int mode)
                    412: {
                    413:        char *str, *s, *pbrk, szOld[MAXPATHLEN] = { 0 };
                    414:        register int cx = -1;
                    415: 
                    416:        if (!csDir)
                    417:                return cx;
                    418: 
                    419:        str = strdup(csDir);
                    420:        if (!str) {
                    421:                LOGERR;
                    422:                return cx;
                    423:        }
                    424: 
                    425:        getcwd(szOld, MAXPATHLEN);
                    426:        if (*str == '/')
                    427:                chdir("/");
                    428: 
                    429:        for (cx = 0, s = strtok_r(str, "/", &pbrk); s; s = strtok_r(NULL, "/", &pbrk)) {
                    430:                if (mkdir(s, mode) == -1) {
                    431:                        if (errno != EEXIST) {
                    432:                                LOGERR;
                    433:                                cx = -1;
                    434:                                goto end;
                    435:                        }
                    436:                } else
                    437:                        cx++;
                    438: 
                    439:                if (chdir(s) == -1) {
                    440:                        LOGERR;
                    441:                        cx = -1;
                    442:                        goto end;
                    443:                }
                    444:        }
                    445: end:
                    446:        chdir(szOld);
                    447:        free(str);
                    448:        return cx;
                    449: }
                    450: 
1.3       misho     451: /*
                    452:  * ioWatchDirLoop() Function for watching changes in directory and fire callback
                    453:  * @csDir = Full directory path
                    454:  * @callback = Callback if raise event! nOp -1 delete, 0 change/move, 1 create
                    455:  * return: -1 error, !=-1 ok, number of total signaled events
                    456: */
                    457: int
                    458: ioWatchDirLoop(const char *csDir, int (*callback)(const char *csName, int nOp))
                    459: {
                    460:        glob_t g[2] = {{ 0 }, { 0 }};
                    461:        int d, kq, n = 0;
                    462:        register int j, i;
                    463:        struct kevent req, chg;
                    464:        char wrk[MAXPATHLEN * 2], str[MAXPATHLEN] = { 0 };
                    465: 
                    466:        if (!csDir || !callback)
                    467:                return 0;
                    468: 
                    469:        strlcpy(str, csDir, MAXPATHLEN);
                    470:        strlcat(str, "/*", MAXPATHLEN);
                    471: 
                    472:        kq = kqueue();
                    473:        if (kq == -1) {
                    474:                LOGERR;
                    475:                return -1;
                    476:        }
                    477:        d = open(csDir, O_RDONLY);
                    478:        if (d == -1) {
                    479:                LOGERR;
                    480:                close(kq);
                    481:                return -1;
                    482:        }
                    483: 
1.4       misho     484:        EV_SET(&req, d, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
1.3       misho     485: 
                    486:        if ((n = glob(str, GLOB_NOCHECK, NULL, &g[0]))) {
                    487:                LOGERR;
                    488:                close(d);
                    489:                close(kq);
                    490:                return -1;
                    491:        } /*else
                    492:                ioDEBUG(3, "Start files %d in %s\n", g[0].gl_matchc, str);*/
                    493: 
                    494:        while (kevent(kq, &req, 1, &chg, 1, NULL) > 0) {
                    495:                /*ioDEBUG(1, "Event:: req=0x%x -> chg=0x%x data=%x\n", req.fflags, chg.fflags, chg.data);*/
                    496: 
                    497:                if (!glob(str, GLOB_NOCHECK, NULL, &g[1])) {
                    498:                        /*ioDEBUG(3, "Diffs %d <> %d\n", g[0].gl_matchc, g[1].gl_matchc);*/
                    499: 
                    500:                        if (g[0].gl_matchc != g[1].gl_matchc) {
                    501:                                /* find new items */
                    502:                                for (j = 0; j < g[1].gl_matchc; j++) {
                    503:                                        for (i = 0; i < g[0].gl_matchc; i++)
                    504:                                                if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
                    505:                                                        break;
                    506:                                        if (i == g[0].gl_matchc) {
                    507:                                                if (callback(g[1].gl_pathv[j], 1) < 0)
                    508:                                                        break;
                    509:                                                else
                    510:                                                        n++;
                    511:                                        }
                    512:                                }
                    513:                                /* find del items */
                    514:                                for (j = 0; j < g[0].gl_matchc; j++) {
                    515:                                        for (i = 0; i < g[1].gl_matchc; i++)
                    516:                                                if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
                    517:                                                        break;
                    518:                                        if (i == g[1].gl_matchc) {
                    519:                                                if (callback(g[0].gl_pathv[j], -1) < 0)
                    520:                                                        break;
                    521:                                                else
                    522:                                                        n++;
                    523:                                        }
                    524:                                }
                    525:                        } else {
                    526:                                /* find chg from items */
                    527:                                for (j = 0; j < g[0].gl_matchc; j++) {
                    528:                                        for (i = 0; i < g[1].gl_matchc; i++)
                    529:                                                if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
                    530:                                                        break;
                    531:                                        if (i == g[1].gl_matchc) {
                    532:                                                strlcpy(wrk, g[0].gl_pathv[j], sizeof wrk);
                    533:                                                strlcat(wrk, ":", sizeof wrk);
                    534:                                        }
                    535:                                }
                    536:                                /* find chg to items */
                    537:                                for (j = 0; j < g[1].gl_matchc; j++) {
                    538:                                        for (i = 0; i < g[0].gl_matchc; i++)
                    539:                                                if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
                    540:                                                        break;
                    541:                                        if (i == g[0].gl_matchc) {
                    542:                                                strlcat(wrk, g[1].gl_pathv[j], sizeof wrk);
                    543:                                                if (callback(wrk, 0) < 0)
                    544:                                                        break;
                    545:                                                else
                    546:                                                        n++;
                    547:                                        }
                    548:                                }
                    549:                        }
                    550: 
                    551:                        globfree(&g[0]);
                    552:                        g[0] = g[1];
                    553:                }
                    554:        }
                    555: 
                    556:        globfree(&g[0]);
                    557:        close(d);
                    558:        close(kq);
                    559:        return n;
                    560: }

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