File:  [ELWIX - Embedded LightWeight unIX -] / libaitio / src / aitio.c
Revision 1.4.2.1: download - view: text, annotated - select for diffs - revision graph
Tue Apr 19 22:32:16 2011 UTC (13 years, 2 months ago) by misho
Branches: io1_7
Diff to: branchpoint 1.4: preferred, unified
added license

    1: /*************************************************************************
    2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
    3: *  by Michael Pounov <misho@elwix.org>
    4: *
    5: * $Author: misho $
    6: * $Id: aitio.c,v 1.4.2.1 2011/04/19 22:32:16 misho Exp $
    7: *
    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 the University 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 THE REGENTS 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: */
   46: #include "global.h"
   47: 
   48: 
   49: int io_Debug;
   50: 
   51: 
   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
   61: inline int io_GetErrno()
   62: {
   63: 	return io_Errno;
   64: }
   65: 
   66: // io_GetError() Get error text of last operation
   67: inline const char *io_GetError()
   68: {
   69: 	return io_Error;
   70: }
   71: 
   72: // io_SetErr() Set error to variables for internal use!!!
   73: inline void io_SetErr(int eno, char *estr, ...)
   74: {
   75: 	va_list lst;
   76: 
   77: 	io_Errno = eno;
   78: 	memset(io_Error, 0, STRSIZ);
   79: 	va_start(lst, estr);
   80: 	vsnprintf(io_Error, STRSIZ, estr, lst);
   81: 	va_end(lst);
   82: }
   83: 
   84: 
   85: /*
   86:  * ioPromptRead() Read data from input h[0] with prompt to output h[1]
   87:  * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
   88:  * @csPrompt = Prompt before input, may be NULL
   89:  * @psData = Readed data
   90:  * @dataLen = Length of data
   91:  * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
   92: */
   93: int ioPromptRead(int *h, const char *csPrompt, char * __restrict psData, int dataLen)
   94: {
   95: 	int ok = 0;
   96: 	FILE *inp, *out;
   97: 	char szLine[BUFSIZ], *pos;
   98: 
   99: 	if (!psData || !dataLen)
  100: 		return -1;
  101: 
  102: 	inp = fdopen(!h ? 0 : h[0], "r");
  103: 	if (!inp) {
  104: 		LOGERR;
  105: 		return -1;
  106: 	}
  107: 	out = fdopen(!h ? 1 : h[1], "w");
  108: 	if (!out) {
  109: 		LOGERR;
  110: 		return -1;
  111: 	}
  112: 
  113: 	while (!ok) {
  114: 		if (csPrompt) {
  115: 			fprintf(out, "%s", csPrompt);
  116: 			fflush(out);
  117: 		}
  118: 
  119: 		memset(szLine, 0, BUFSIZ);
  120: 		if (!fgets(szLine, BUFSIZ, inp)) {
  121: 			clearerr(inp);
  122: 			fpurge(out);
  123: 			fflush(out);
  124: 			return 0;
  125: 		}
  126: 
  127: 		if ((pos = strchr(szLine, '\n')))
  128: 			*pos = 0;
  129: 
  130: 		strlcpy(psData, szLine, dataLen);
  131: 		ok = 1;
  132: 	}
  133: 
  134: 	return pos - szLine;
  135: }
  136: 
  137: /*
  138:  * ioPromptPassword() Read password from input h[0] with prompt to output h[1]
  139:  * @h = file handles h[0] = input, h[1] = output, if NULL use stdin, stdout
  140:  * @csPrompt = Prompt before input, may be NULL
  141:  * @psPass = Readed password
  142:  * @passLen = Length of password
  143:  * @confirm = Confirm password, 0 - get password, !=0 Ask for confirmation
  144:  * return: 0 EOF; -1 error:: can`t read; >0 count of readed chars
  145: */
  146: int ioPromptPassword(int *h, const char *csPrompt, char * __restrict psPass, int passLen, int confirm)
  147: {
  148: 	int ret, ok = 0;
  149: 	FILE *inp, *out;
  150: 	char szLine[2][STRSIZ];
  151: 	struct sgttyb tty_state;
  152: 
  153: 	if (!psPass || !passLen)
  154: 		return -1;
  155: 
  156: 	inp = fdopen(!h ? 0 : h[0], "r");
  157: 	if (!inp) {
  158: 		LOGERR;
  159: 		return -1;
  160: 	}
  161: 	out = fdopen(!h ? 1 : h[1], "w");
  162: 	if (!out) {
  163: 		LOGERR;
  164: 		return -1;
  165: 	}
  166: 
  167: 	if (ioctl(fileno(inp), TIOCGETP, &tty_state) == -1) {
  168: 		LOGERR;
  169: 		return -1;
  170: 	} else {
  171: 		tty_state.sg_flags &= ~ECHO;
  172: 		if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
  173: 			LOGERR;
  174: 			return -1;
  175: 		}
  176: 	}
  177: 
  178: 	while (!ok) {
  179: 		switch ((ret = ioPromptRead(h, (!csPrompt || !*csPrompt) ? "Password:" : csPrompt, 
  180: 						szLine[0], STRSIZ))) {
  181: 			case -1:
  182: 				LOGERR;
  183: 				ok = -1;
  184: 			case 0:
  185: 				goto next;
  186: 		}
  187: 		if (confirm) {
  188: 			fprintf(out, "\n");
  189: 			fflush(out);
  190: 
  191: 			switch (ioPromptRead(h, "Password confirm:", szLine[1], STRSIZ)) {
  192: 				case -1:
  193: 					LOGERR;
  194: 					ok = -1;
  195: 					goto next;
  196: 				case 0:
  197: 				default:
  198: 					if (strcmp(szLine[0], szLine[1])) {
  199: 						fprintf(out, "\n\07\07Mismatch - Try again!\n");
  200: 						fflush(out);
  201: 						continue;
  202: 					}
  203: 			}
  204: 		}
  205: 
  206: 		strlcpy(psPass, szLine[0], passLen);
  207: 		ok = ret;
  208: 		fprintf(out, "\n");
  209: 		fflush(out);
  210: 	}
  211: 
  212: next:
  213: 	tty_state.sg_flags |= ECHO;
  214: 	if (ioctl(fileno(inp), TIOCSETP, &tty_state) == -1) {
  215: 		LOGERR;
  216: 		return -1;
  217: 	}
  218: 
  219: 	return ok;
  220: }
  221: 
  222: /*
  223:  * ioRegexVerify() Function for verify data match in regex expression
  224:  * @csRegex = Regulare expression pattern
  225:  * @csData = Data for check and verify
  226:  * @startPos = Return start positions
  227:  * @endPos = Return end positions
  228:  * return: NULL not match or error; !=NULL begin of matched data
  229: */
  230: const char *ioRegexVerify(const char *csRegex, const char *csData, int *startPos, int *endPos)
  231: {
  232: 	regex_t re;
  233: 	regmatch_t match;
  234: 	char szErr[STRSIZ];
  235: 	int ret, flg;
  236: 	const char *pos;
  237: 
  238: 	if (!csRegex || !csData)
  239: 		return NULL;
  240: 
  241: 	if ((ret = regcomp(&re, csRegex, REG_EXTENDED))) {
  242: 		regerror(ret, &re, szErr, STRSIZ);
  243: 		io_SetErr(ret, "Error:: %s\n", szErr);
  244: 		regfree(&re);
  245: 		return NULL;
  246: 	}
  247: 
  248: 	for (ret = flg = 0, pos = csData; !(ret = regexec(&re, pos, 1, &match, flg)); 
  249: 			pos += match.rm_eo, flg = REG_NOTBOL) {
  250: 		if (startPos)
  251: 			*startPos = match.rm_so;
  252: 		if (endPos)
  253: 			*endPos = match.rm_eo;
  254: 
  255: 		pos += match.rm_so;
  256: 		break;
  257: 	}
  258: 
  259: 	if (ret) {
  260: 		regerror(ret, &re, szErr, STRSIZ);
  261: 		io_SetErr(ret, "Error:: %s\n", szErr);
  262: 		pos = NULL;
  263: 	}
  264: 
  265: 	regfree(&re);
  266: 	return pos;
  267: }
  268: 
  269: /*
  270:  * ioRegexGet() Function for get data match in regex expression
  271:  * @csRegex = Regulare expression pattern
  272:  * @csData = Data from get
  273:  * @psString = Returned string if match
  274:  * @strLen = Length of string
  275:  * return: 0 not match; >0 count of returned chars
  276: */
  277: int ioRegexGet(const char *csRegex, const char *csData, char * __restrict psString, int strLen)
  278: {
  279: 	int sp, ep, len;
  280: 	const char *str;
  281: 
  282: 	if (!csRegex || !csData)
  283: 		return -1;
  284: 
  285: 	str = ioRegexVerify(csRegex, csData, &sp, &ep);
  286: 	if (!str)
  287: 		return 0;
  288: 
  289: 	len = ep - sp;
  290: 	if (psString && strLen) {
  291: 		memset(psString, 0, strLen);
  292: 		strncpy(psString, str, strLen <= len ? strLen - 1 : len);
  293: 	}
  294: 
  295: 	return len;
  296: }
  297: 
  298: /*
  299:  * ioRegexReplace() Function for replace data match in regex expression with newdata
  300:  * @csRegex = Regulare expression pattern
  301:  * @csData = Source data
  302:  * @csNew = Data for replace
  303:  * return: NULL not match or error; !=NULL allocated new string, must be free after use!
  304: */
  305: char *ioRegexReplace(const char *csRegex, const char *csData, const char *csNew)
  306: {
  307: 	int sp, ep, len;
  308: 	char *str = NULL;
  309: 
  310: 	if (!csRegex || !csData)
  311: 		return NULL;
  312: 
  313: 	if (!ioRegexVerify(csRegex, csData, &sp, &ep))
  314: 		return NULL;
  315: 
  316: 	// ___ before match
  317: 	len = sp + 1;
  318: 	str = malloc(len);
  319: 	if (!str) {
  320: 		LOGERR;
  321: 		return NULL;
  322: 	} else
  323: 		strlcpy(str, csData, len);
  324: 	// * replace match *
  325: 	if (csNew) {
  326: 		len += strlen(csNew);
  327: 		str = realloc(str, len);
  328: 		if (!str) {
  329: 			LOGERR;
  330: 			return NULL;
  331: 		} else
  332: 			strlcat(str, csNew, len);
  333: 	}
  334: 	// after match ___
  335: 	len += strlen(csData) - ep;
  336: 	str = realloc(str, len);
  337: 	if (!str) {
  338: 		LOGERR;
  339: 		return NULL;
  340: 	} else
  341: 		strlcat(str, csData + ep, len);
  342: 
  343: 	return str;
  344: }
  345: 
  346: /*
  347:  * ioVarAst() Function for evaluate string like asterisk variable "{text[:[-]#[:#]]}"
  348:  * @csString = Input string
  349:  * return: NULL error, !=NULL Allocated new string evaluated from input string, must be free()
  350: */
  351: char *
  352: ioVarAst(const char *csString)
  353: {
  354: 	char *ext, *str, *out = NULL;
  355: 	int e[2] = { 0 };
  356: 
  357: 	if (!csString)
  358: 		return NULL;
  359: 
  360: 	if (!strchr(csString, '{') || !strrchr(csString, '}')) {
  361: 		memset(io_Error, 0, STRSIZ);
  362: 		snprintf(io_Error, STRSIZ, "Error:: Invalid input string format ... "
  363: 				"must be like {text[:[-]#[:#]]}");
  364: 		io_Errno = EINVAL;
  365: 		return NULL;
  366: 	} else {
  367: 		str = strdup(strchr(csString, '{') + 1);
  368: 		*strrchr(str, '}') = 0;
  369: 	}
  370: 
  371: 	if ((ext = strchr(str, ':'))) {
  372: 		*ext++ = 0;
  373: 		e[0] = strtol(ext, NULL, 0);
  374: 		if ((ext = strchr(ext, ':')))
  375: 			e[1] = strtol(++ext, NULL, 0);
  376: 
  377: 		/* make cut prefix */
  378: 		if (e[0] >= 0)
  379: 			ext = str + e[0];
  380: 		else
  381: 			ext = str + strlen(str) + e[0];
  382: 		/* make cut suffix */
  383: 		if (e[1] > 0)
  384: 			*(ext + e[1]) = 0;
  385: 	} else
  386: 		/* ok, clear show */
  387: 		ext = str;
  388: 
  389: 	out = strdup(ext);
  390: 	free(str);
  391: 
  392: 	return out;
  393: }
  394: 
  395: 
  396: /*
  397:  * ioMkDir() Function for racursive directory creation and validation
  398:  * @csDir = Full directory path
  399:  * @mode = Mode for directory creation if missing dir
  400:  * return: -1 error, 0 directory path exist, >0 created missing dirs
  401: */
  402: int
  403: ioMkDir(const char *csDir, int mode)
  404: {
  405: 	char *str, *s, *pbrk, szOld[MAXPATHLEN] = { 0 };
  406: 	register int cx = -1;
  407: 
  408: 	if (!csDir)
  409: 		return cx;
  410: 
  411: 	str = strdup(csDir);
  412: 	if (!str) {
  413: 		LOGERR;
  414: 		return cx;
  415: 	}
  416: 
  417: 	getcwd(szOld, MAXPATHLEN);
  418: 	if (*str == '/')
  419: 		chdir("/");
  420: 
  421: 	for (cx = 0, s = strtok_r(str, "/", &pbrk); s; s = strtok_r(NULL, "/", &pbrk)) {
  422: 		if (mkdir(s, mode) == -1) {
  423: 			if (errno != EEXIST) {
  424: 				LOGERR;
  425: 				cx = -1;
  426: 				goto end;
  427: 			}
  428: 		} else
  429: 			cx++;
  430: 
  431: 		if (chdir(s) == -1) {
  432: 			LOGERR;
  433: 			cx = -1;
  434: 			goto end;
  435: 		}
  436: 	}
  437: end:
  438: 	chdir(szOld);
  439: 	free(str);
  440: 	return cx;
  441: }
  442: 
  443: /*
  444:  * ioWatchDirLoop() Function for watching changes in directory and fire callback
  445:  * @csDir = Full directory path
  446:  * @callback = Callback if raise event! nOp -1 delete, 0 change/move, 1 create
  447:  * return: -1 error, !=-1 ok, number of total signaled events
  448: */
  449: int
  450: ioWatchDirLoop(const char *csDir, int (*callback)(const char *csName, int nOp))
  451: {
  452: 	glob_t g[2] = {{ 0 }, { 0 }};
  453: 	int d, kq, n = 0;
  454: 	register int j, i;
  455: 	struct kevent req, chg;
  456: 	char wrk[MAXPATHLEN * 2], str[MAXPATHLEN] = { 0 };
  457: 
  458: 	if (!csDir || !callback)
  459: 		return 0;
  460: 
  461: 	strlcpy(str, csDir, MAXPATHLEN);
  462: 	strlcat(str, "/*", MAXPATHLEN);
  463: 
  464: 	kq = kqueue();
  465: 	if (kq == -1) {
  466: 		LOGERR;
  467: 		return -1;
  468: 	}
  469: 	d = open(csDir, O_RDONLY);
  470: 	if (d == -1) {
  471: 		LOGERR;
  472: 		close(kq);
  473: 		return -1;
  474: 	}
  475: 
  476: 	EV_SET(&req, d, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE, 0, 0);
  477: 
  478: 	if ((n = glob(str, GLOB_NOCHECK, NULL, &g[0]))) {
  479: 		LOGERR;
  480: 		close(d);
  481: 		close(kq);
  482: 		return -1;
  483: 	} /*else
  484: 		ioDEBUG(3, "Start files %d in %s\n", g[0].gl_matchc, str);*/
  485: 
  486: 	while (kevent(kq, &req, 1, &chg, 1, NULL) > 0) {
  487: 		/*ioDEBUG(1, "Event:: req=0x%x -> chg=0x%x data=%x\n", req.fflags, chg.fflags, chg.data);*/
  488: 
  489: 		if (!glob(str, GLOB_NOCHECK, NULL, &g[1])) {
  490: 			/*ioDEBUG(3, "Diffs %d <> %d\n", g[0].gl_matchc, g[1].gl_matchc);*/
  491: 
  492: 			if (g[0].gl_matchc != g[1].gl_matchc) {
  493: 				/* find new items */
  494: 				for (j = 0; j < g[1].gl_matchc; j++) {
  495: 					for (i = 0; i < g[0].gl_matchc; i++)
  496: 						if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
  497: 							break;
  498: 					if (i == g[0].gl_matchc) {
  499: 						if (callback(g[1].gl_pathv[j], 1) < 0)
  500: 							break;
  501: 						else
  502: 							n++;
  503: 					}
  504: 				}
  505: 				/* find del items */
  506: 				for (j = 0; j < g[0].gl_matchc; j++) {
  507: 					for (i = 0; i < g[1].gl_matchc; i++)
  508: 						if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
  509: 							break;
  510: 					if (i == g[1].gl_matchc) {
  511: 						if (callback(g[0].gl_pathv[j], -1) < 0)
  512: 							break;
  513: 						else
  514: 							n++;
  515: 					}
  516: 				}
  517: 			} else {
  518: 				/* find chg from items */
  519: 				for (j = 0; j < g[0].gl_matchc; j++) {
  520: 					for (i = 0; i < g[1].gl_matchc; i++)
  521: 						if (!strcmp(g[1].gl_pathv[i], g[0].gl_pathv[j]))
  522: 							break;
  523: 					if (i == g[1].gl_matchc) {
  524: 						strlcpy(wrk, g[0].gl_pathv[j], sizeof wrk);
  525: 						strlcat(wrk, ":", sizeof wrk);
  526: 					}
  527: 				}
  528: 				/* find chg to items */
  529: 				for (j = 0; j < g[1].gl_matchc; j++) {
  530: 					for (i = 0; i < g[0].gl_matchc; i++)
  531: 						if (!strcmp(g[0].gl_pathv[i], g[1].gl_pathv[j]))
  532: 							break;
  533: 					if (i == g[0].gl_matchc) {
  534: 						strlcat(wrk, g[1].gl_pathv[j], sizeof wrk);
  535: 						if (callback(wrk, 0) < 0)
  536: 							break;
  537: 						else
  538: 							n++;
  539: 					}
  540: 				}
  541: 			}
  542: 
  543: 			globfree(&g[0]);
  544: 			g[0] = g[1];
  545: 		}
  546: 	}
  547: 
  548: 	globfree(&g[0]);
  549: 	close(d);
  550: 	close(kq);
  551: 	return n;
  552: }

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