diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2012-09-04 14:51:35 +0200 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2012-09-04 14:51:35 +0200 |
commit | c596f1c1b2b6df18a9209d436a8255d96f437b54 (patch) | |
tree | c98aea6002cf929ca9a69e63de1954320115d6a2 | |
parent | b473bae2d7bd907b5e9a6ee9fc7cadf92dfe69b8 (diff) | |
download | rsyslog-c596f1c1b2b6df18a9209d436a8255d96f437b54.tar.gz rsyslog-c596f1c1b2b6df18a9209d436a8255d96f437b54.tar.bz2 rsyslog-c596f1c1b2b6df18a9209d436a8255d96f437b54.zip |
new ruleengine: PROP and PRI legacy filter structures properly created
-rw-r--r-- | grammar/grammar.y | 23 | ||||
-rw-r--r-- | grammar/parserif.h | 1 | ||||
-rw-r--r-- | grammar/rainerscript.c | 86 | ||||
-rw-r--r-- | grammar/rainerscript.h | 25 | ||||
-rw-r--r-- | runtime/conf.c | 111 | ||||
-rw-r--r-- | runtime/conf.h | 4 | ||||
-rw-r--r-- | runtime/rsconf.c | 5 |
7 files changed, 155 insertions, 100 deletions
diff --git a/grammar/grammar.y b/grammar/grammar.y index 65a6e8dc..a9f179e0 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -148,20 +148,15 @@ script: stmt { $$ = $1; } stmt: actlst { $$ = $1; } | STOP { $$ = cnfstmtNew(S_STOP); } | IF expr THEN block { $$ = cnfstmtNew(S_IF); - $$->d.cond.expr = $2; - $$->d.cond.t_then = $4; - $$->d.cond.t_else = NULL; } + $$->d.s_if.expr = $2; + $$->d.s_if.t_then = $4; + $$->d.s_if.t_else = NULL; } | IF expr THEN block ELSE block { $$ = cnfstmtNew(S_IF); - $$->d.cond.expr = $2; - $$->d.cond.t_then = $4; - $$->d.cond.t_else = $6; } - | PRIFILT block { $$ = cnfstmtNew(S_PRIFILT); - $$->printable = $1; - $$->d.cond.expr = $1; - $$->d.cond.t_then = $2; } - | PROPFILT block { $$ = cnfstmtNew(S_PROPFILT); - $$->d.cond.expr = $1; - $$->d.cond.t_then = $2; } + $$->d.s_if.expr = $2; + $$->d.s_if.t_then = $4; + $$->d.s_if.t_else = $6; } + | PRIFILT block { $$ = cnfstmtNewPRIFILT($1, $2); } + | PROPFILT block { $$ = cnfstmtNewPROPFILT($1, $2); } block: stmt { $$ = $1; } | '{' script '}' { $$ = $2; } actlst: s_act { $$ = $1; } @@ -170,7 +165,7 @@ s_act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfstmtNew(S_ACT); $$->printable="action()"; dbgprintf("RRRR: action object\n"); } | LEGACY_ACTION { $$ = cnfstmtNew(S_ACT); - $$->printable = $1; + $$->printable = (uchar*) $1; dbgprintf("RRRR: legacy action\n"); } expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } diff --git a/grammar/parserif.h b/grammar/parserif.h index 3b2a9a7b..aa271ec4 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -16,7 +16,6 @@ extern int yylineno; */ void cnfDoObj(struct cnfobj *o); void cnfDoScript(struct cnfstmt *script); -void cnfDoRule(struct cnfrule *rule); void cnfDoCfsysline(char *ln); void cnfDoBSDTag(char *ln); void cnfDoBSDHost(char *ln); diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index b127b906..0e3f30ae 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -37,6 +37,7 @@ #include <libestr.h> #include "rsyslog.h" #include "rainerscript.h" +#include "conf.h" #include "parserif.h" #include "grammar.h" #include "queue.h" @@ -47,6 +48,37 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) +static char* +getFIOPName(unsigned iFIOP) +{ + char *pRet; + switch(iFIOP) { + case FIOP_CONTAINS: + pRet = "contains"; + break; + case FIOP_ISEQUAL: + pRet = "isequal"; + break; + case FIOP_STARTSWITH: + pRet = "startswith"; + break; + case FIOP_REGEX: + pRet = "regex"; + break; + case FIOP_EREREGEX: + pRet = "ereregex"; + break; + case FIOP_ISEMPTY: + pRet = "isempty"; + break; + default: + pRet = "NOP"; + break; + } + return pRet; +} + + void readConfFile(FILE *fp, es_str_t **str) { @@ -1531,26 +1563,42 @@ cnfstmtPrint(struct cnfstmt *root, int indent) break; case S_IF: doIndent(indent); dbgprintf("IF\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); + cnfexprPrint(stmt->d.s_if.expr, indent+1); doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); - if(stmt->d.cond.t_else != NULL) { + cnfstmtPrint(stmt->d.s_if.t_then, indent+1); + if(stmt->d.s_if.t_else != NULL) { doIndent(indent); dbgprintf("ELSE\n"); - cnfstmtPrint(stmt->d.cond.t_else, indent+1); + cnfstmtPrint(stmt->d.s_if.t_else, indent+1); } doIndent(indent); dbgprintf("END IF\n"); break; case S_PRIFILT: doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); //cnfexprPrint(stmt->d.cond.expr, indent+1); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); + cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); doIndent(indent); dbgprintf("END PRIFILT\n"); break; case S_PROPFILT: doIndent(indent); dbgprintf("PROPFILT\n"); - cnfexprPrint(stmt->d.cond.expr, indent+1); + doIndent(indent); dbgprintf("\tProperty.: '%s'\n", + propIDToName(stmt->d.s_propfilt.propID)); + if(stmt->d.s_propfilt.propName != NULL) { + char *cstr; + cstr = es_str2cstr(stmt->d.s_propfilt.propName, NULL); + doIndent(indent); + dbgprintf("\tCEE-Prop.: '%s'\n", cstr); + free(cstr); + } + doIndent(indent); dbgprintf("\tOperation: "); + if(stmt->d.s_propfilt.isNegated) + dbgprintf("NOT "); + dbgprintf("'%s'\n", getFIOPName(stmt->d.s_propfilt.operation)); + if(stmt->d.s_propfilt.pCSCompValue != NULL) { + doIndent(indent); dbgprintf("\tValue....: '%s'\n", + rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue)); + } doIndent(indent); dbgprintf("THEN\n"); - cnfstmtPrint(stmt->d.cond.t_then, indent+1); + cnfstmtPrint(stmt->d.s_propfilt.t_then, indent+1); doIndent(indent); dbgprintf("END PROPFILT\n"); break; default: @@ -1605,6 +1653,30 @@ cnfstmtNew(unsigned s_type) return cnfstmt; } +struct cnfstmt * +cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_PRIFILT)) != NULL) { + cnfstmt->printable = (uchar*)strdup(prifilt); + cnfstmt->d.s_prifilt.t_then = t_then; + DecodePRIFilter((uchar*)prifilt, cnfstmt->d.s_prifilt.pmask); + } + return cnfstmt; +} + +struct cnfstmt * +cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_PROPFILT)) != NULL) { + cnfstmt->printable = (uchar*)strdup(propfilt); + cnfstmt->d.s_propfilt.t_then = t_then; + DecodePropFilter((uchar*)propfilt, cnfstmt); + } + return cnfstmt; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 2d4d9271..89d7c050 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -3,7 +3,14 @@ #include <stdio.h> #include <libestr.h> #include <typedefs.h> +#include <sys/types.h> +#include <regex.h> +//#include "stringbuf.h" +/* TODO: make this hack cleaner... we have circular definitions, so we need: */ + + +#define LOG_NFACILITIES 24 /* current number of syslog facilities */ #define CNFFUNC_MAX_ARGS 32 /**< maximum number of arguments that any function can have (among * others, this is used to size data structures). @@ -163,7 +170,20 @@ struct cnfstmt { /* base statement, for simple types */ struct cnfexpr *expr; struct cnfstmt *t_then; struct cnfstmt *t_else; - } cond; + } s_if; + struct { + uchar pmask[LOG_NFACILITIES+1]; /* priority mask */ + struct cnfstmt *t_then; + } s_prifilt; + struct { + fiop_t operation; + regex_t *regex_cache;/* cache for compiled REs, if used */ + struct cstr_s *pCSCompValue;/* value to "compare" against */ + sbool isNegated; + uintTiny propID;/* ID of the requested property */ + es_str_t *propName;/* name of property for CEE-based filters */ + struct cnfstmt *t_then; + } s_propfilt; struct action_s *act; } d; }; @@ -297,7 +317,10 @@ void cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst); struct cnfstmt * cnfstmtNew(unsigned s_type); void cnfstmtPrint(struct cnfstmt *stmt, int indent); struct cnfstmt* scriptAddStmt(struct cnfstmt *root, struct cnfstmt *s); +struct objlst* objlstAdd(struct objlst *root, struct cnfobj *o); char *rmLeadingSpace(char *s); +struct cnfstmt * cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then); +struct cnfstmt * cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then); rsRetVal initRainerscript(void); /* debug helper */ diff --git a/runtime/conf.c b/runtime/conf.c index 488d1b86..7ad8f529 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -65,13 +65,13 @@ #include "ruleset.h" #include "rsconf.h" #include "unicode-helper.h" +#include "rainerscript.h" #ifdef OS_SOLARIS # define NAME_MAX MAXNAMELEN #endif /* forward definitions */ -//static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ @@ -326,14 +326,9 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int } -/* Helper to cfline(). This function takes the filter part of a traditional, PRI - * based line and decodes the PRIs given in the selector line. It processed the - * line up to the beginning of the action part. A pointer to that beginnig is - * passed back to the caller. - * rgerhards 2005-09-15 - */ +/* Decode a traditional PRI filter */ /* GPLv3 - stems back to sysklogd */ -rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) +rsRetVal DecodePRIFilter(uchar *pline, uchar pmask[]) { uchar *p; register uchar *q; @@ -347,22 +342,15 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) DEFiRet; ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ISOBJ_TYPE_assert(pRule, rule); - dbgprintf(" - traditional PRI filter '%s'\n", *pline); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ + dbgprintf("Decoding traditional PRI filter '%s'\n", pline); - pRule->f_filter_type = FILTER_PRI; - /* Note: file structure is pre-initialized to zero because it was - * created with calloc()! - */ for (i = 0; i <= LOG_NFACILITIES; i++) { - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + pmask[i] = TABLE_NOPRI; } /* scan through the list of selectors */ - for (p = *pline; *p && *p != '\t' && *p != ' ';) { + for (p = pline; *p && *p != '\t' && *p != ' ';) { /* find the end of this facility name list */ for (q = p; *q && *q != '\t' && *q++ != '.'; ) continue; @@ -411,28 +399,28 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) for (i = 0; i <= LOG_NFACILITIES; i++) { if ( pri == INTERNAL_NOPRI ) { if ( ignorepri ) - pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; + pmask[i] = TABLE_ALLPRI; else - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + pmask[i] = TABLE_NOPRI; } else if ( singlpri ) { if ( ignorepri ) - pRule->f_filterData.f_pmask[i] &= ~(1<<pri); + pmask[i] &= ~(1<<pri); else - pRule->f_filterData.f_pmask[i] |= (1<<pri); + pmask[i] |= (1<<pri); } else { if ( pri == TABLE_ALLPRI ) { if ( ignorepri ) - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + pmask[i] = TABLE_NOPRI; else - pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; + pmask[i] = TABLE_ALLPRI; } else { if ( ignorepri ) for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i] &= ~(1<<i2); + pmask[i] &= ~(1<<i2); else for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i] |= (1<<i2); + pmask[i] |= (1<<i2); } } } @@ -447,27 +435,27 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) if ( pri == INTERNAL_NOPRI ) { if ( ignorepri ) - pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; + pmask[i >> 3] = TABLE_ALLPRI; else - pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; + pmask[i >> 3] = TABLE_NOPRI; } else if ( singlpri ) { if ( ignorepri ) - pRule->f_filterData.f_pmask[i >> 3] &= ~(1<<pri); + pmask[i >> 3] &= ~(1<<pri); else - pRule->f_filterData.f_pmask[i >> 3] |= (1<<pri); + pmask[i >> 3] |= (1<<pri); } else { if ( pri == TABLE_ALLPRI ) { if ( ignorepri ) - pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; + pmask[i >> 3] = TABLE_NOPRI; else - pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; + pmask[i >> 3] = TABLE_ALLPRI; } else { if ( ignorepri ) for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i >> 3] &= ~(1<<i2); + pmask[i >> 3] &= ~(1<<i2); else for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i >> 3] |= (1<<i2); + pmask[i >> 3] |= (1<<i2); } } } @@ -478,11 +466,6 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) p = q; } - /* skip to action part */ - while (*p == '\t' || *p == ' ') - p++; - - *pline = p; RETiRet; } @@ -492,7 +475,7 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) * of the action part. A pointer to that beginnig is passed back to the caller. * rgerhards 2005-09-15 */ -rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) +rsRetVal DecodePropFilter(uchar *pline, struct cnfstmt *stmt) { rsParsObj *pPars; cstr_t *pCSCompOp; @@ -501,16 +484,11 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) int iOffset; /* for compare operations */ ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(f != NULL); - dbgprintf(" - property-based filter '%s'\n", *pline); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - f->f_filter_type = FILTER_PROP; + dbgprintf("Decoding property-based filter '%s'\n", pline); /* create parser object starting with line string without leading colon */ - if((iRet = rsParsConstructFromSz(&pPars, (*pline)+1)) != RS_RET_OK) { + if((iRet = rsParsConstructFromSz(&pPars, pline+1)) != RS_RET_OK) { errmsg.LogError(0, iRet, "Error %d constructing parser object - ignoring selector", iRet); return(iRet); } @@ -522,15 +500,15 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) rsParsDestruct(pPars); return(iRet); } - iRet = propNameToID(pCSPropName, &f->f_filterData.prop.propID); + iRet = propNameToID(pCSPropName, &stmt->d.s_propfilt.propID); if(iRet != RS_RET_OK) { errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); rsParsDestruct(pPars); return(iRet); } - if(f->f_filterData.prop.propID == PROP_CEE) { + if(stmt->d.s_propfilt.propID == PROP_CEE) { /* in CEE case, we need to preserve the actual property name */ - if((f->f_filterData.prop.propName = + if((stmt->d.s_propfilt.propName = es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { cstrDestruct(&pCSPropName); return(RS_RET_ERR); @@ -553,38 +531,38 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) */ if(rsCStrLen(pCSCompOp) > 0) { if(*rsCStrGetBufBeg(pCSCompOp) == '!') { - f->f_filterData.prop.isNegated = 1; + stmt->d.s_propfilt.isNegated = 1; iOffset = 1; /* ignore '!' */ } else { - f->f_filterData.prop.isNegated = 0; + stmt->d.s_propfilt.isNegated = 0; iOffset = 0; } } else { - f->f_filterData.prop.isNegated = 0; + stmt->d.s_propfilt.isNegated = 0; iOffset = 0; } if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { - f->f_filterData.prop.operation = FIOP_CONTAINS; + stmt->d.s_propfilt.operation = FIOP_CONTAINS; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { - f->f_filterData.prop.operation = FIOP_ISEQUAL; + stmt->d.s_propfilt.operation = FIOP_ISEQUAL; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { - f->f_filterData.prop.operation = FIOP_ISEMPTY; + stmt->d.s_propfilt.operation = FIOP_ISEMPTY; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { - f->f_filterData.prop.operation = FIOP_STARTSWITH; + stmt->d.s_propfilt.operation = FIOP_STARTSWITH; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { - f->f_filterData.prop.operation = FIOP_REGEX; + stmt->d.s_propfilt.operation = FIOP_REGEX; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) { - f->f_filterData.prop.operation = FIOP_EREREGEX; + stmt->d.s_propfilt.operation = FIOP_EREREGEX; } else { errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector", (char*) rsCStrGetSzStrNoNULL(pCSCompOp)); } rsCStrDestruct(&pCSCompOp); /* no longer needed */ - if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { + if(stmt->d.s_propfilt.operation != FIOP_ISEMPTY) { /* read compare value */ - iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); + iRet = parsQuotedCStr(pPars, &stmt->d.s_propfilt.pCSCompValue); if(iRet != RS_RET_OK) { errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); rsParsDestruct(pPars); @@ -592,17 +570,6 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) } } - /* skip to action part */ - if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - - /* cleanup */ - *pline = *pline + rsParsGetParsePointer(pPars) + 1; - /* we are adding one for the skipped initial ":" */ - return rsParsDestruct(pPars); } diff --git a/runtime/conf.h b/runtime/conf.h index 018d9111..04b69bc9 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -65,8 +65,8 @@ rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pO /* more dirt to cover the new config interface (will go away...) */ rsRetVal cflineProcessTagSelector(uchar **pline); rsRetVal cflineProcessHostSelector(uchar **pline); -rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule); -rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f); +rsRetVal DecodePRIFilter(uchar *pline, uchar pmask[]); +rsRetVal DecodePropFilter(uchar *pline, struct cnfstmt *stmt); rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction); extern EHostnameCmpMode eDfltHostnameCmpMode; extern cstr_t *pDfltHostnameCmp; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 0f31e515..5f1980fd 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -370,9 +370,6 @@ parser_errmsg(char *fmt, ...) va_start(ap, fmt); if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf)) errBuf[sizeof(errBuf)-1] = '\0'; -dbgprintf("XXXX: msg: %s\n", errBuf); -dbgprintf("XXXX: cnfcurrfn: %s\n", cnfcurrfn); -dbgprintf("XXXX: yylineno: %d\n", yylineno); errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, "error during parsing file %s, on or before line %d: %s", cnfcurrfn, yylineno, errBuf); @@ -415,6 +412,7 @@ void cnfDoObj(struct cnfobj *o) cnfobjDestruct(o); } +#if 0 void cnfDoRule(struct cnfrule *cnfrule) { rule_t *pRule; @@ -465,6 +463,7 @@ finalize_it: //TODO: do something with error states cnfruleDestruct(cnfrule); } +#endif void cnfDoScript(struct cnfstmt *script) { |