File:  [ELWIX - Embedded LightWeight unIX -] / libaitio / src / aitio.c
Revision 1.3.4.1: download - view: text, annotated - select for diffs - revision graph
Tue Apr 19 19:58:25 2011 UTC (13 years, 2 months ago) by misho
Branches: io1_6
Diff to: branchpoint 1.3: preferred, unified
strict small fixes
- added new header
- change NULL to 0

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

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