X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=userv.git;a=blobdiff_plain;f=parser.c;h=b2c2b03896c41bb3c3450cf8d12d08d1b8f6128e;hp=0505474cf8e244cef09af0e12e215681f09733cc;hb=5723a49791587f497380fee82d9c481faff2099c;hpb=4544c87c6355037a095e296b5280ccb3ff25ac4b diff --git a/parser.c b/parser.c index 0505474..b2c2b03 100644 --- a/parser.c +++ b/parser.c @@ -6,7 +6,7 @@ * about m4 quoting &c., but we have to #include it so that the C * objects from the lexer are available. * - * Copyright (C)1996-1997 Ian Jackson + * Copyright (C)1996-1999 Ian Jackson * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by @@ -98,7 +98,7 @@ static void errwhere(struct parser_state *tstate, char *bufput, int bufputlen) { tstate->filename,tstate->reportlineno); } -void parseerrprint(const char *fmt, ...) { +int parseerrprint(const char *fmt, ...) { va_list al; char errmsg[MAX_ERRMSG_LEN]; @@ -107,6 +107,8 @@ void parseerrprint(const char *fmt, ...) { vsnytprintfcat(errmsg,sizeof(errmsg),fmt,al); senderrmsg(errmsg,eh.handling); va_end(al); + + return tokv_error; } static int unexpected(int found, int wanted, const char *wantedstr) { @@ -115,13 +117,11 @@ static int unexpected(int found, int wanted, const char *wantedstr) { */ if (found == wanted) return 0; if (found == tokv_error) return found; - parseerrprint("found %s, expected %s",printtoken(found),wantedstr); - return tokv_error; + return parseerrprint("found %s, expected %s",printtoken(found),wantedstr); } static int stringoverflow(const char *where) { - parseerrprint("string buffer became far too large building %s",where); - return tokv_error; + return parseerrprint("string buffer became far too large building %s",where); } /* @@ -136,43 +136,55 @@ static void freecharparray(char **array) { free(array); } +static void countnewlines(void) { + char *p; + for (p=yytext; *p; p++) + if (*p == '\n') + cstate->lineno++; +} + static int dequote(char *inplace) { char *p, *q, buf[4], *bep; int v; - + p=q=inplace; assert(*p++ = '"'); while (*p && *p != '"') { if (*p != '\\') { *q++= *p++; continue; } switch (*++p) { - case 'n': *q++= '\n'; continue; - case 'r': *q++= '\r'; continue; - case 't': *q++= '\t'; continue; + case 'n': *q++= '\n'; p++; continue; + case 'r': *q++= '\r'; p++; continue; + case 't': *q++= '\t'; p++; continue; case 'x': - assert(buf[0]= *++p); assert(buf[1]= *++p); buf[2]= 0; - v= strtoul(buf,&bep,16); assert(bep == buf+2); - assert(!(v & ~0xff)); *q++= v; p++; continue; + p++; + if (!((buf[0]= *p++) && (buf[1]= *p++))) + return parseerrprint("quoted string ends inside \\x sequence"); + buf[2]= 0; + v= strtoul(buf,&bep,16); + if (bep != buf+2) + return parseerrprint("invalid \\ sequence \\x%s in quoted string",buf); + assert(!(v & ~0xff)); + *q++= v; + continue; default: - if (isalpha(*p)) { - parseerrprint("unknown \\ sequence \\%c in quoted string",*p); - return tokv_error; - } else if (isdigit(*p)) { - assert(buf[0]= *++p); assert(buf[1]= *++p); assert(buf[2]= *++p); + if (isalpha(*p)) + return parseerrprint("unknown \\ sequence \\%c in quoted string",*p); + if (isdigit(*p)) { + if (!((buf[0]= *p++) && (buf[1]= *p++) && (buf[2]= *p++))) abort(); buf[3]= 0; v= strtoul(buf,&bep,8); - if (bep != buf+3 || (v & ~0xff)); { - parseerrprint("invalid \\ sequence \\%s in quoted string",buf); - return tokv_error; - } - *q++= v; p++; continue; + if (bep != buf+3 || (v & ~0xff)) + return parseerrprint("invalid \\ sequence \\%s in quoted string",buf); + *q++= v; continue; } else if (ispunct(*p)) { *q++= *p++; continue; } else { while (*p==' ' || *p=='\t') p++; - assert(*p=='\n'); + v= *p++; assert(v=='\n'); } } } assert(*p); assert(!*++p); + *q++= 0; return tokv_quotedstring; } @@ -336,8 +348,8 @@ static int paa_pathargs(const char **path_r, char ***newargs_r) { } if (used>=size) { if (used >= MAX_ARGSDEFVAR) { - parseerrprint("far too many arguments to service program"); - r= tokv_error; goto error; + r= parseerrprint("far too many arguments to service program"); + goto error; } size= (used+5)<<1; newargs= xrealloc(newargs,sizeof(char*)*(size+1)); @@ -358,6 +370,7 @@ static int paa_message(const char **message_r) { /* Returned value is invalidated by repeated calls. */ static char *buildbuf; static int buildbuflen; + const char *usetext; int r, tl; @@ -367,14 +380,13 @@ static int paa_message(const char **message_r) { buildbuf[0]= 0; for (;;) { r= yylex(); if (r == tokv_error) return r; - if (r == tokv_eof) { - parseerrprint("unexpected end of file in message text"); - return tokv_error; - } + if (r == tokv_eof) + return parseerrprint("unexpected end of file in message text"); if (r == tokv_newline) break; - tl+= strlen(yytext); + usetext= r == tokv_lwsp ? " " : yytext; + tl+= strlen(usetext); if (makeroom(&buildbuf,&buildbuflen,tl)) return stringoverflow("message"); - strcat(buildbuf,yytext); + strcat(buildbuf,usetext); } *message_r= buildbuf; return 0; @@ -396,8 +408,7 @@ static int skiptoeol(void) { if (token == tokv_newline) return 0; if (token == tokv_error) return token; assert(token == tokv_eof); - parseerrprint("unexpected end of file while looking for end of line"); - return tokv_error; + return parseerrprint("unexpected end of file while looking for end of line"); } static int skip(int allowce) { @@ -425,9 +436,8 @@ static int skip(int allowce) { r= skip(token); if (r & tokt_exception) return r; } } else if (!(token & tokt_directive) && !(token & tokt_condop)) { - parseerrprint("not a directive (or conditional operator) " - "while looking for control structure end"); - return tokv_error; + return parseerrprint("not a directive (or conditional operator) " + "while looking for control structure end"); } r= skiptoeol(); if (r) return r; } @@ -487,7 +497,7 @@ static int pf_service(int ptoken, char ***rvalues) { } static int pf_callinguser(int ptoken, char ***rvalues) { - return parm_usernameuid(rvalues,logname,request_mbuf.callinguid); + return parm_usernameuid(rvalues,loginname,request_mbuf.callinguid); } static int pf_serviceuser(int ptoken, char ***rvalues) { @@ -602,10 +612,8 @@ int pcf_grep(int ctoken, char *const *pv, int *rtrue) { r= paa_1path(&cp); if (r) return r; file= fopen(cp,"r"); - if (!file) { - parseerrprint("unable to open file `%s' for grep: %s",cp,strerror(errno)); - return tokv_error; - } + if (!file) + return parseerrprint("unable to open file `%s' for grep: %s",cp,strerror(errno)); maxlen= 0; for (pp= pv; *pp; pp++) { l= strlen(*pp); if (l > maxlen) maxlen= l; } buf= xmalloc(maxlen+2); actrue= 0; c= 0; @@ -838,8 +846,7 @@ int df_reset(int dtoken) { r= pa_mnl(); if (r) return r; r= parse_string(RESET_CONFIGURATION,"",1); - assert(!r); - return 0; + return r; } int dfg_fdwant(int dtoken) { @@ -851,21 +858,16 @@ int dfg_fdwant(int dtoken) { if (!(r & tokt_fdrange)) return unexpected(r,-1,"file descriptor range"); fdmin= lr_min; fdmax= lr_max; if (fdmin<0 || fdmin>MAX_ALLOW_FD || - (fdmax != -1 && fdmax<0) || fdmax>MAX_ALLOW_FD) { - parseerrprint("file descriptor in range is negative or far too large"); - return tokv_error; - } + (fdmax != -1 && fdmax<0) || fdmax>MAX_ALLOW_FD) + return parseerrprint("file descriptor in range is negative or far too large"); r= yylex(); if (r == tokv_error) return r; if (r == tokv_newline) { - if (needreadwrite > 0) { - parseerrprint("read or write is required"); - return tokv_error; - } + if (needreadwrite > 0) + return parseerrprint("read or write is required"); havereadwrite= 0; } else if (r == tokv_lwsp) { - if (needreadwrite < 0) { - parseerrprint("read or write not allowed"); return tokv_error; - } + if (needreadwrite < 0) + return parseerrprint("read or write not allowed"); r= yylex(); if (r == tokv_error) return r; if (!(r & tokt_readwrite)) return unexpected(r,-1,"read or write (or perhaps newline)"); @@ -877,7 +879,8 @@ int dfg_fdwant(int dtoken) { ensurefdarray(fdmin); if (fdmax == -1) { if (!(dtoken == tokv_word_rejectfd || dtoken == tokv_word_ignorefd)) - parseerrprint("unspecified maximum only allowed with reject-fd and ignore-fd"); + return parseerrprint("unspecified maximum only allowed" + " with reject-fd and ignore-fd"); fdmax= fdarrayused-1; restfdwantstate= dtoken; restfdwantrw= havereadwrite; @@ -934,10 +937,8 @@ int df_errorstofile(int dtoken) { r= paa_1path(&cp); if (r) return r; file= fopen(cp,"a"); - if (!file) { - parseerrprint("unable to open error log file `%s': %s",cp,strerror(errno)); - return tokv_error; - } + if (!file) + return parseerrprint("unable to open error log file `%s': %s",cp,strerror(errno)); if (setvbuf(file,0,_IOLBF,MAX_ERRMSG_LEN)) { parseerrprint("unable to set line buffering on errors file: %s",strerror(errno)); fclose(file); return tokv_error; @@ -972,11 +973,10 @@ int df_include(int dtoken) { r= paa_1path(&cp); if (r) return r; r= parse_file(cp,&found); if (r) return r; if (found || dtoken == tokv_word_includeifexist) return 0; - parseerrprint(dtoken == tokv_word_includesysconfig ? - "system configuration file `%s' does not exist" : - "included file `%s' does not exist", - cp); - return tokv_error; + return parseerrprint(dtoken == tokv_word_includesysconfig ? + "system configuration file `%s' does not exist" : + "included file `%s' does not exist", + cp); } int df_includedirectory(int dtoken) { @@ -986,14 +986,14 @@ int df_includedirectory(int dtoken) { int r, cpl, tel, c, found; DIR *d; struct dirent *de; - const char *p, *cp; + const char *p, *cpget; + char *cp; - r= paa_1path(&cp); if (r) return r; - d= opendir(cp); - if (!d) { - parseerrprint("unable to open directory `%s': %s",cp,strerror(errno)); - return tokv_error; - } + r= paa_1path(&cpget); if (r) return r; + d= opendir(cpget); + if (!d) + return parseerrprint("unable to open directory `%s': %s",cpget,strerror(errno)); + cp= xstrsave(cpget); cpl= strlen(cp); while ((de= readdir(d))) { tel= strlen(de->d_name); @@ -1002,60 +1002,72 @@ int df_includedirectory(int dtoken) { if (!*p || !isalnum(*p)) continue; while ((c= *++p)) if (!(isalnum(c) || c=='-')) break; if (c) continue; - if (makeroom(&buildbuf,&buildbuflen,cpl+1+tel+1)) - return stringoverflow("pathname in directory"); + if (makeroom(&buildbuf,&buildbuflen,cpl+1+tel+1)) { + stringoverflow("pathname in directory"); + r= tokv_error; goto x_err; + } snyprintf(buildbuf,buildbuflen,"%s/%s",cp,de->d_name); - r= parse_file(buildbuf,&found); if (r) { closedir(d); return r; } + r= parse_file(buildbuf,&found); if (r) goto x_err; if (!found) { - parseerrprint("unable to open file `%s' in included directory `%s': %s", - de->d_name,cp,strerror(errno)); - closedir(d); - return tokv_error; + r= parseerrprint("unable to open file `%s' in included directory `%s': %s", + de->d_name,cp,strerror(errno)); + goto x_err; } } if (closedir(d)) { parseerrprint("error closing directory `%s': %s",cp,strerror(errno)); + free(cp); return tokv_error; } + free(cp); return 0; + +x_err: + closedir(d); + free(cp); + return r; } int df_includelookup(int dtoken) { static char *buildbuf=0; int buildbuflen=0; - char **parmvalues, **pp, *p, *q; - const char *cp; + char **parmvalues, **pp, *p, *q, *cp; + const char *cpget; struct stat stab; int r, done, thisdone, cpl, c; r= pa_mwsp(); if (r) return r; r= pa_parameter(&parmvalues,0); if (r) return r; - r= paa_1path(&cp); if (r) { freecharparray(parmvalues); return r; } - if (stat(cp,&stab)) { - parseerrprint("unable to access directory `%s': %s",cp,strerror(errno)); + r= paa_1path(&cpget); if (r) { freecharparray(parmvalues); return r; } + if (stat(cpget,&stab)) { + parseerrprint("unable to access directory `%s': %s",cpget,strerror(errno)); freecharparray(parmvalues); return tokv_error; } if (!S_ISDIR(stab.st_mode)) { - parseerrprint("object `%s' is not a directory or link to one",cp); + parseerrprint("object `%s' is not a directory or link to one",cpget); freecharparray(parmvalues); return tokv_error; } done= 0; + cp= xstrsave(cpget); cpl= strlen(cp); if (!parmvalues[0]) { - if (makeroom(&buildbuf,&buildbuflen,cpl+1+sizeof(NONEINCLUDELOOKUP))) - return stringoverflow("pathname in directory for lookup of undefined parameter"); + if (makeroom(&buildbuf,&buildbuflen,cpl+1+sizeof(NONEINCLUDELOOKUP))) { + stringoverflow("pathname in directory for lookup of undefined parameter"); + r= tokv_error; goto x_err; + } snyprintf(buildbuf,buildbuflen,"%s/" NONEINCLUDELOOKUP,cp); - r= parse_file(buildbuf,&thisdone); - if (r) { freecharparray(parmvalues); return r; } + r= parse_file(buildbuf,&thisdone); if (r) goto x_err; if (thisdone) done= 1; } else { for (pp=parmvalues; *pp && (!done || dtoken == tokv_word_includelookupall); pp++) { if (makeroom(&buildbuf,&buildbuflen, - cpl+1+strlen(*pp)*2+3+sizeof(EMPTYINCLUDELOOKUP)+1)) - return stringoverflow("pathname in directory for lookup"); + cpl+1+strlen(*pp)*2+3+sizeof(EMPTYINCLUDELOOKUP)+1)) { + stringoverflow("pathname in directory for lookup"); + r= tokv_error; goto x_err; + } strcpy(buildbuf,cp); p= *pp; q= buildbuf+cpl; *q++= '/'; @@ -1064,26 +1076,38 @@ int df_includelookup(int dtoken) { } else { if (*p=='.') *q++= ':'; while ((c= *p++)) { - if (c=='/') { *q++= ':'; c='-'; } - else if (c==':') { *q++= ':'; } + if (c=='/') { + *q++= ':'; + c= '-'; + } else if (!((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + c == '-' || c == '_')) { + *q++= ':'; + } *q++= c; } *q++= 0; } r= parse_file(buildbuf,&thisdone); - if (r) { freecharparray(parmvalues); return r; } + if (r) goto x_err; if (thisdone) done= 1; } } - freecharparray(parmvalues); if (!done) { if (makeroom(&buildbuf,&buildbuflen, - cpl+1+sizeof(DEFAULTINCLUDELOOKUP))) - return stringoverflow("pathname in directory for lookup of default"); + cpl+1+sizeof(DEFAULTINCLUDELOOKUP))) { + stringoverflow("pathname in directory for lookup of default"); + r= tokv_error; goto x_err; + } snyprintf(buildbuf,buildbuflen,"%s/" DEFAULTINCLUDELOOKUP,cp); - r= parse_file(buildbuf,0); if (r) return r; + r= parse_file(buildbuf,0); if (r) goto x_err; } - return 0; + r= 0; + +x_err: + freecharparray(parmvalues); + free(cp); + return r; } /* Control constructs */ @@ -1158,8 +1182,7 @@ int df_cd(int dtoken) { r= paa_1path(&cp); if (r) return r; if (!chdir(cp)) return 0; - parseerrprint("unable to change directory to `%s': %s",cp,strerror(errno)); - return tokv_error; + return parseerrprint("unable to change directory to `%s': %s",cp,strerror(errno)); } int df_userrcfile(int dtoken) { @@ -1185,8 +1208,7 @@ int df_error(int dtoken) { int r; r= paa_message(&mp); if (r) return r; - parseerrprint("`error' directive: %s",mp); - return tokv_error; + return parseerrprint("`error' directive: %s",mp); } int df_eof(int dtoken) { @@ -1272,43 +1294,37 @@ static int parse_file(const char *string, int *didexist) { char *filename; struct stat newstab; - if (fileparselevel >= MAX_INCLUDE_NEST) { - parseerrprint("too many nested levels of included files"); - return tokv_error; - } + if (fileparselevel >= MAX_INCLUDE_NEST) + return parseerrprint("too many nested levels of included files"); file= fopen(string,"r"); if (!file) { if (errno == ENOENT) { if (didexist) *didexist= 0; return 0; } - parseerrprint("unable to open config file `%s': %s",string,strerror(errno)); - return tokv_error; + return parseerrprint("unable to open config file `%s': %s",string,strerror(errno)); } r= fstat(fileno(file),&newstab); if (r) syscallerror("unable to fstat new file"); for (checkrecurse= cstate; checkrecurse; checkrecurse= checkrecurse->upstate) { if (!checkrecurse->filestab.st_mode) continue; if (newstab.st_dev==checkrecurse->filestab.st_dev && newstab.st_ino==checkrecurse->filestab.st_ino) { - parseerrprint("recursion detected - config file `%s' calls itself",string); fclose(file); - return tokv_error; + return parseerrprint("recursion detected - config file `%s' calls itself",string); } } if (didexist) *didexist= 1; - filename= xstrsave(string); ybuf= yy_create_buffer(file,YY_BUF_SIZE); if (!ybuf) syscallerror("unable to create flex buffer for file"); + filename= xstrsave(string); parser_push(&usestate,filename,&newstab,ybuf,0); fileparselevel++; r= parser(0); - if (ferror(file)) { - parseerrprint("error reading configuration file `%s'",string); - r= tokv_error; - } + if (ferror(file)) + r= parseerrprint("error reading configuration file `%s'",string); fileparselevel--; parser_pop();