Diff for /libaitio/src/aitio.c between versions 1.1 and 1.17.8.3

version 1.1, 2010/02/23 22:54:52 version 1.17.8.3, 2016/08/10 14:19:50
Line 1 Line 1
 /*************************************************************************  /*************************************************************************
* (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>* (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
*  by Michael Pounov <misho@openbsd-bg.org>*  by Michael Pounov <misho@elwix.org>
 *  *
 * $Author$  * $Author$
 * $Id$  * $Id$
 *  *
*************************************************************************/**************************************************************************
 The ELWIX and AITNET software is distributed under the following
 terms:
 
 All of the documentation and software included in the ELWIX and AITNET
 Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
 
 Copyright 2004 - 2016
         by Michael Pounov <misho@elwix.org>.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
 3. All advertising materials mentioning features or use of this software
    must display the following acknowledgement:
 This product includes software developed by Michael Pounov <misho@elwix.org>
 ELWIX - Embedded LightWeight unIX and its contributors.
 4. Neither the name of AITNET nor the names of its contributors
    may be used to endorse or promote products derived from this software
    without specific prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 */
 #include "global.h"  #include "global.h"
   
   
Line 18  char io_Error[STRSIZ]; Line 55  char io_Error[STRSIZ];
   
   
 // io_GetErrno() Get error code of last operation  // io_GetErrno() Get error code of last operation
inline int io_GetErrno()int
 io_GetErrno()
 {  {
         return io_Errno;          return io_Errno;
 }  }
   
 // io_GetError() Get error text of last operation  // io_GetError() Get error text of last operation
inline const char *io_GetError()const char *
 io_GetError()
 {  {
         return io_Error;          return io_Error;
 }  }
   
 // io_SetErr() Set error to variables for internal use!!!  // io_SetErr() Set error to variables for internal use!!!
inline void io_SetErr(int eno, char *estr, ...)void
 io_SetErr(int eno, char *estr, ...)
 {  {
         va_list lst;          va_list lst;
   
         io_Errno = eno;          io_Errno = eno;
        memset(io_Error, 0, STRSIZ);        memset(io_Error, 0, sizeof io_Error);
         va_start(lst, estr);          va_start(lst, estr);
        vsnprintf(io_Error, STRSIZ, estr, lst);        vsnprintf(io_Error, sizeof io_Error, estr, lst);
         va_end(lst);          va_end(lst);
 }  }
   
   
 /*  /*
 * ioPromptRead() Read data from input h[0] with prompt to output h[1] * ioPromptRead() - Read data from input h[0] with prompt to output h[1]
  *
  * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout   * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
  * @csPrompt = Prompt before input, may be NULL   * @csPrompt = Prompt before input, may be NULL
  * @psData = Readed data   * @psData = Readed data
  * @dataLen = Length of data   * @dataLen = Length of data
  * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars   * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
 */  */
int ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen)int
 ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen)
 {  {
         int ok = 0;          int ok = 0;
         FILE *inp, *out;          FILE *inp, *out;
Line 79  int ioPromptRead(int *h, const char *csPrompt, char *  Line 121  int ioPromptRead(int *h, const char *csPrompt, char * 
                 memset(szLine, 0, BUFSIZ);                  memset(szLine, 0, BUFSIZ);
                 if (!fgets(szLine, BUFSIZ, inp)) {                  if (!fgets(szLine, BUFSIZ, inp)) {
                         clearerr(inp);                          clearerr(inp);
   #ifdef HAVE_FPURGE
                         fpurge(out);                          fpurge(out);
   #else
                           __fpurge(out);
   #endif
                         fflush(out);                          fflush(out);
                         return 0;                          return 0;
                 }                  }
Line 95  int ioPromptRead(int *h, const char *csPrompt, char *  Line 141  int ioPromptRead(int *h, const char *csPrompt, char * 
 }  }
   
 /*  /*
 * ioPromptPassword() Read password from input h[0] with prompt to output h[1] * ioPromptPassword() - Read password from input h[0] with prompt to output h[1]
  *
  * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout   * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
  * @csPrompt = Prompt before input, may be NULL   * @csPrompt = Prompt before input, may be NULL
  * @psPass = Readed password   * @psPass = Readed password
Line 103  int ioPromptRead(int *h, const char *csPrompt, char *  Line 150  int ioPromptRead(int *h, const char *csPrompt, char * 
  * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation   * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation
  * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars   * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
 */  */
int ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm)int
 ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm)
 {  {
         int ret, ok = 0;          int ret, ok = 0;
         FILE *inp, *out;          FILE *inp, *out;
         char szLine[2][STRSIZ];          char szLine[2][STRSIZ];
   #ifndef __linux__
         struct sgttyb tty_state;          struct sgttyb tty_state;
   #else
           struct termios o;
   #endif
   
         if (!psPass || !passLen)          if (!psPass || !passLen)
                 return -1;                  return -1;
Line 124  int ioPromptPassword(int *h, const char *csPrompt, cha Line 176  int ioPromptPassword(int *h, const char *csPrompt, cha
                 return -1;                  return -1;
         }          }
   
   #ifndef __linux__
         if (ioctl(fileno(inp), TIOCGETP, &tty_state) == -1) {          if (ioctl(fileno(inp), TIOCGETP, &tty_state) == -1) {
                 LOGERR;                  LOGERR;
                 return -1;                  return -1;
Line 134  int ioPromptPassword(int *h, const char *csPrompt, cha Line 187  int ioPromptPassword(int *h, const char *csPrompt, cha
                         return -1;                          return -1;
                 }                  }
         }          }
   #else
           if (tcgetattr(fileno(inp), &o) == -1) {
                   LOGERR;
                   return -1;
           } else {
                   o.c_lflag &= ~ECHO;
                   if (tcsetattr(fileno(inp), TCSANOW, &o) == -1) {
                           LOGERR;
                           return -1;
                   }
           }
   #endif
   
         while (!ok) {          while (!ok) {
                 switch ((ret = ioPromptRead(h, (!csPrompt || !*csPrompt) ? "Password:" : csPrompt,                   switch ((ret = ioPromptRead(h, (!csPrompt || !*csPrompt) ? "Password:" : csPrompt, 
Line 170  int ioPromptPassword(int *h, const char *csPrompt, cha Line 235  int ioPromptPassword(int *h, const char *csPrompt, cha
         }          }
   
 next:  next:
   #ifndef __linux__
         tty_state.sg_flags |= ECHO;          tty_state.sg_flags |= ECHO;
         if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {          if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
                 LOGERR;                  LOGERR;
                 return -1;                  return -1;
         }          }
   #else
           o.c_lflag |= ECHO;
           if (tcsetattr(fileno(inp), TCSANOW, &o) == -1) {
                   LOGERR;
                   return -1;
           }
   #endif
   
         return ok;          return ok;
 }  }
   
 /*  /*
 * ioRegexVerify() Function for verify data match in regex expression * ioMkDir() - Function for racursive directory creation and validation
 * @csRegex = Regulare expression pattern *
 * @csData = Data for check and verify * @csDir = Full directory path
 * @startPos = Return start positions * @mode = Mode for directory creation if missing dir
 * @endPos = Return end positions * return: -1 error, 0 directory path exist, >0 created missing dirs
 * return: NULL not match or error; !=NULL begin of matched data 
 */  */
const char *ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos)int
 ioMkDir(const char *csDir, int mode)
 {  {
        regex_t re;        char *str, *s, *pbrk, szOld[MAXPATHLEN] = { 0 };
        regmatch_t match;        register int cx = -1;
        char szErr[STRSIZ]; 
        int ret, flg; 
        const char *pos; 
   
        if (!csRegex || !csData)        if (!csDir)
                return NULL;                return cx;
   
        if ((ret = regcomp(&re, csRegex, REG_EXTENDED))) {        str = e_strdup(csDir);
                regerror(ret, &re, szErr, STRSIZ);        if (!str) {
                io_SetErr(ret, "Error:: %s\n", szErr);                LOGERR;
                regfree(&re);                return cx;
                return NULL; 
         }          }
   
        for (ret = flg = 0, pos = csData; !(ret = regexec(&re, pos, 1, &match, flg));         getcwd(szOld, MAXPATHLEN);
                        pos += match.rm_eo, flg = REG_NOTBOL) {        if (*str == '/')
                if (startPos)                chdir("/");
                        *startPos = match.rm_so; 
                if (endPos) 
                        *endPos = match.rm_eo; 
   
                pos += match.rm_so;        for (cx = 0, s = strtok_r(str, "/", &pbrk); s; s = strtok_r(NULL, "/", &pbrk)) {
                break;                if (mkdir(s, mode) == -1) {
                         if (errno != EEXIST) {
                                 LOGERR;
                                 cx = -1;
                                 goto end;
                         }
                 } else
                         cx++;
 
                 if (chdir(s) == -1) {
                         LOGERR;
                         cx = -1;
                         goto end;
                 }
         }          }
   end:
           chdir(szOld);
           e_free(str);
           return cx;
   }
   
        if (ret) {/*
                regerror(ret, &re, szErr, STRSIZ); * ioWatchDirLoop() - Function for watching changes in directory and fire callback
                io_SetErr(ret, "Error:: %s\n", szErr); *
                pos = NULL; * @csDir = Full directory path
  * @callback = Callback if raise event! nOp -1 delete, 0 change/move, 1 create
  * return: -1 error, !=-1 ok, number of total signaled events
 */
 int
 ioWatchDirLoop(const char *csDir, int (*callback)(const char *csName, int nOp))
 {
         glob_t g[2] = {{ 0 }, { 0 }};
         int d, n = 0;
         register int j, i;
 #ifndef __linux__
         int kq;
         struct kevent req, chg;
 #endif
         char wrk[MAXPATHLEN * 2], str[MAXPATHLEN] = { 0 };
 
         if (!csDir || !callback)
                 return 0;
 
         strlcpy(str, csDir, MAXPATHLEN);
         strlcat(str, "/*", MAXPATHLEN);
 
         d = open(csDir, O_RDONLY);
         if (d == -1) {
                 LOGERR;
                 return -1;
         }          }
   
        regfree(&re);#ifndef __linux__
        return pos;        kq = kqueue();
         if (kq == -1) {
                 LOGERR;
                 close(d);
                 return -1;
         }
 
         EV_SET(&req, d, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
 #endif
 
         if ((n = glob(str, GLOB_NOCHECK, NULL, &g[0]))) {
                 LOGERR;
                 close(d);
 #ifndef __linux__
                 close(kq);
 #endif
                 return -1;
         } /*else
                 ioDEBUG(3, "Start files %d in %s\n", g[0].gl_matchc, str);*/
 
 #ifndef __linux__
         while (kevent(kq, &req, 1, &chg, 1, NULL) > 0) {
                 /*ioDEBUG(1, "Event:: req=0x%x -> chg=0x%x data=%x\n", req.fflags, chg.fflags, chg.data);*/
 
                 if (!glob(str, GLOB_NOCHECK, NULL, &g[1])) {
                         /*ioDEBUG(3, "Diffs %d <> %d\n", g[0].gl_matchc, g[1].gl_matchc);*/
 
                         if (g[0].gl_matchc != g[1].gl_matchc) {
                                 /* find new items */
                                 for (j = 0; j < g[1].gl_matchc; j++) {
                                         for (i = 0; i < g[0].gl_matchc; i++)
                                                 if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
                                                         break;
                                         if (i == g[0].gl_matchc) {
                                                 if (callback(g[1].gl_pathv[j], 1) < 0)
                                                         break;
                                                 else
                                                         n++;
                                         }
                                 }
                                 /* find del items */
                                 for (j = 0; j < g[0].gl_matchc; j++) {
                                         for (i = 0; i < g[1].gl_matchc; i++)
                                                 if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
                                                         break;
                                         if (i == g[1].gl_matchc) {
                                                 if (callback(g[0].gl_pathv[j], -1) < 0)
                                                         break;
                                                 else
                                                         n++;
                                         }
                                 }
                         } else {
                                 /* find chg from items */
                                 for (j = 0; j < g[0].gl_matchc; j++) {
                                         for (i = 0; i < g[1].gl_matchc; i++)
                                                 if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
                                                         break;
                                         if (i == g[1].gl_matchc) {
                                                 strlcpy(wrk, g[0].gl_pathv[j], sizeof wrk);
                                                 strlcat(wrk, ":", sizeof wrk);
                                         }
                                 }
                                 /* find chg to items */
                                 for (j = 0; j < g[1].gl_matchc; j++) {
                                         for (i = 0; i < g[0].gl_matchc; i++)
                                                 if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
                                                         break;
                                         if (i == g[0].gl_matchc) {
                                                 strlcat(wrk, g[1].gl_pathv[j], sizeof wrk);
                                                 if (callback(wrk, 0) < 0)
                                                         break;
                                                 else
                                                         n++;
                                         }
                                 }
                         }
 
                         globfree(&g[0]);
                         g[0] = g[1];
                 }
         }
 #endif
 
         globfree(&g[0]);
 #ifndef __linux__
         close(kq);
 #endif
         close(d);
         return n;
 }  }
   
 /*  /*
 * ioRegexGet() Function for get data match in regex expression * ioCreatePIDFile() - Create PID file
 * @csRegex = Regulare expression pattern *
 * @csData = Data from get * @csName = PID filename
 * @psString = Returned string if match * @ifExists = !=0 if filename exists return error
 * @strLen = Length of string * return: -1 error or 0 ok
 * return: 0 not match; >0 count of returned chars */
*/int
int ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen)ioCreatePIDFile(const char *csName, int ifExists)
 {  {
        int sp, ep, len;        int fd;
        const char *str;        char str[STRSIZ] = { 0 };
   
        if (!csRegex || !csData)        if (!csName)
                 return -1;                  return -1;
   
        str = ioRegexVerify(csRegex, csData, &sp, &ep);        fd = open(csName, O_WRONLY | O_CREAT | (ifExists ? O_EXCL : 0), 0644);
        if (!str)        if (fd == -1) {
                 LOGERR;
                 return -1;
         }
         snprintf(str, sizeof str, "%d", getpid());
         write(fd, str, strlen(str));
         close(fd);
         return 0;
 }
 
 
 /*
  * ioSendFile() - AITNET sendfile() userland implementation, not dependant from OS
  *
  * @s = socket
  * @csFile = file for send
  * @sendLen = bytes to send, if 0 send all data
  * @offset = start file offset
  * @sndbuf = SO_SNDBUF value, if 0 use default
  * return: 0 error, >0 ok, sended bytes
  */
 size_t
 ioSendFile(int s, const char *csFile, size_t sendLen, off_t offset, int sndbuf)
 {
         void *addr;
         int fd;
         size_t len = 0;
         register size_t off = 0;
 
         if (!csFile)
                 return 0;                  return 0;
   
        len = ep - sp;        if (sndbuf)
        if (psString && strLen) {                if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof sndbuf) == -1) {
                memset(psString, 0, strLen);                        LOGERR;
                strncpy(psString, str, strLen <= len ? strLen - 1 : len);                        return 0;
                 }
 
         fd = open(csFile, O_RDONLY);
         if (fd == -1) {
                 LOGERR;
                 return 0;
         }          }
           if (!sendLen) {
                   sendLen = lseek(fd, 0, SEEK_END);
                   if (sendLen == -1) {
                           LOGERR;
                           close(fd);
                           return 0;
                   }
           }
           addr = mmap(NULL, sendLen, PROT_READ, MAP_SHARED, fd, offset);
           if (addr == MAP_FAILED) {
                   LOGERR;
                   close(fd);
                   return 0;
           } else
                   close(fd);
   
           while (off < sendLen && (len = write(s, addr + off, sendLen - off)) != -1)
                   off += len;
           if (len == -1) {
                   LOGERR;
                   munmap(addr, sendLen);
                   return 0;
           } else
                   len = off;
   
           if (len != sendLen) {
                   io_SetErr(ECANCELED, "Different sizes - request %u bytes, actually sended %u bytes\n", 
                                   sendLen, len);
                   len ^= len;
           }
   
           munmap(addr, sendLen);
         return len;          return len;
 }  }
   
 /*  /*
 * ioRegexReplace() Function for replace data match in regex expression with newdata * ioRecvFile() - Receive file from socket, fastest (zero-copy) way
 * @csRegex = Regulare expression pattern *
 * @csData = Source data * @s = socket
 * @csNew = Data for replace * @csFile = file for receive
 * return: NULL not match or error; !=NULL allocated new string, must be free after use! * @recvLen = receive bytes
*/ * @over = overwrite file if exists with mode like 0644
char *ioRegexReplace(const char *csRegex, const char *csData, const char *csNew) * @rcvbuf = SO_RCVBUF value, if 0 use default
  * return: 0 error, >0 ok, received bytes
  */
 size_t
 ioRecvFile(int s, const char *csFile, size_t recvLen, int over, int rcvbuf)
 {  {
        int sp, ep, len;        void *addr;
         int fd;
         size_t len = 0;
         register size_t off = 0;
         struct pollfd pfd = { s, POLLIN | POLLPRI, 0 };
 
         if (!csFile || !recvLen)
                 return 0;
         if (!over && !access(csFile, F_OK))
                 return 0;
 
         if (rcvbuf)
                 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof rcvbuf) == -1) {
                         LOGERR;
                         return 0;
                 }
 
         fd = open(csFile, O_WRONLY | O_CREAT | O_TRUNC, over);
         if (fd == -1) {
                 LOGERR;
                 unlink(csFile);
                 return 0;
         }
         if (ftruncate(fd, recvLen) == -1) {
                 LOGERR;
                 close(fd);
                 unlink(csFile);
                 return 0;
         }
         addr = mmap(NULL, recvLen, PROT_WRITE, MAP_SHARED, fd, 0);
         if (addr == MAP_FAILED) {
                 LOGERR;
                 close(fd);
                 unlink(csFile);
                 return 0;
         } else
                 close(fd);
 
         while (off < recvLen && poll(&pfd, 1, RECV_TIMEOUT) != -1)
                 while (off < recvLen && (len = read(s, addr + off, recvLen - off)) != -1)
                         off += len;
         if (len == -1) {
                 LOGERR;
                 munmap(addr, recvLen);
                 unlink(csFile);
                 return 0;
         } else
                 len = off;
 
         if (len != recvLen)
                 io_SetErr(EAGAIN, "Different sizes - request %u bytes, actually received %u bytes\n", 
                                 recvLen, len);
 
         munmap(addr, recvLen);
         return len;
 }
 
 /*
  * ioRealFileName() - Get real file name
  *
  * @fname = filename
  * return: =NULL error or !=NULL real filename, should be free with e_free()
  */
 char *
 ioRealFileName(const char *fname)
 {
         char *str = NULL;          char *str = NULL;
           struct stat sb;
   
        if (!csRegex || !csData)        if (!fname)
                 return NULL;                  return NULL;
   
        if (!ioRegexVerify(csRegex, csData, &sp, &ep))        str = e_malloc(MAXPATHLEN);
                return NULL; 
 
        // ___ before match 
        len = sp + 1; 
        str = malloc(len); 
         if (!str) {          if (!str) {
                LOGERR;                io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
                 return NULL;                  return NULL;
         } else          } else
                strlcpy(str, csData, len);                memset(str, 0, MAXPATHLEN);
        // * replace match *        if (readlink(fname, str, MAXPATHLEN) == -1) {
        if (csNew) {                if (stat(fname, &sb) == -1) {
                len += strlen(csNew); 
                str = realloc(str, len); 
                if (!str) { 
                         LOGERR;                          LOGERR;
                           e_free(str);
                         return NULL;                          return NULL;
                 } else                  } else
                        strlcat(str, csNew, len);                        strlcpy(str, fname, MAXPATHLEN);
         }          }
         // after match ___  
         len += strlen(csData) - ep;  
         str = realloc(str, len);  
         if (!str) {  
                 LOGERR;  
                 return NULL;  
         } else  
                 strlcat(str, csData + ep, len);  
   
         return str;          return str;
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.17.8.3


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