/* * parser_utils.c * * Copyright (c) 2018-2019 Eric Vidal <eric@obarun.org> * * All rights reserved. * * This file is part of Obarun. It is subject to the license terms in * the LICENSE file found in the top-level directory of this * distribution. * This file may not be copied, modified, propagated, or distributed * except according to the terms contained in the LICENSE file./ */ #include <66/parser.h> #include <string.h> #include <unistd.h>//getuid #include <stdlib.h> #include <stdint.h> #include <sys/types.h> #include <pwd.h> #include <errno.h> #include <stdio.h> #include <oblibs/bytes.h> #include <oblibs/string.h> #include <oblibs/files.h> #include <oblibs/log.h> #include <oblibs/types.h> #include <oblibs/mill.h> #include <oblibs/environ.h> #include <oblibs/sastr.h> #include <skalibs/sig.h> #include <skalibs/genalloc.h> #include <skalibs/stralloc.h> #include <skalibs/bytestr.h> #include <skalibs/diuint32.h> #include <skalibs/djbunix.h> #include <66/config.h> #include <66/constants.h> #include <66/enum.h> #include <66/utils.h>//MYUID stralloc keep = STRALLOC_ZERO ;//sv_alltype data stralloc deps = STRALLOC_ZERO ;//sv_name depends //genalloc gadeps = GENALLOC_ZERO ;//unsigned int, pos in deps genalloc gasv = GENALLOC_ZERO ;//sv_alltype general /********************************** * function helper declaration * *******************************/ void section_setsa(int id, stralloc_ref *p,section_t *sa) ; int section_get_skip(char const *s,size_t pos,int nline) ; int section_get_id(stralloc *secname, char const *string,size_t *pos,int *id) ; int key_get_next_id(stralloc *sa, char const *string,size_t *pos) ; int get_clean_val(keynocheck *ch) ; int get_enum(char const *string, keynocheck *ch) ; int get_timeout(keynocheck *ch,uint32_t *ui) ; int get_uint(keynocheck *ch,uint32_t *ui) ; int check_valid_runas(keynocheck *check) ; void parse_err(int ierr,keynocheck *check) ; int parse_line(stralloc *sa, size_t *pos) ; int parse_bracket(stralloc *sa,size_t *pos) ; /********************************** * freed function * *******************************/ void sv_alltype_free(sv_alltype *sv) { stralloc_free(&sv->saenv) ; *&sv->saenv = stralloc_zero ; } void keynocheck_free(keynocheck *nocheck) { stralloc_free(&nocheck->val) ; *nocheck = keynocheck_zero ; } void section_free(section_t *sec) { stralloc_free(&sec->main) ; stralloc_free(&sec->start) ; stralloc_free(&sec->stop) ; stralloc_free(&sec->logger) ; stralloc_free(&sec->environment) ; } void freed_parser(void) { stralloc_free(&keep) ; stralloc_free(&deps) ; // genalloc_free(unsigned int,&gadeps) ; for (unsigned int i = 0 ; i < genalloc_len(sv_alltype,&gasv) ; i++) sv_alltype_free(&genalloc_s(sv_alltype,&gasv)[i]) ; } /********************************** * Mill utilities * *******************************/ parse_mill_t MILL_FIRST_BRACKET = \ { \ .search = "(", .searchlen = 1, \ .end = ")", .endlen = 1, \ .inner.debug = "first_bracket" } ; parse_mill_t MILL_GET_AROBASE_KEY = \ { \ .open = '@', .close = '=', .keepopen = 1, \ .flush = 1, \ .forceclose = 1, .skip = " \t\r", .skiplen = 3, \ .forceskip = 1, .inner.debug = "get_arobase_key" } ; parse_mill_t MILL_GET_COMMENTED_KEY = \ { \ .search = "#", .searchlen = 1, \ .end = "@", .endlen = 1, .inner.debug = "get_commented_key" } ; parse_mill_t MILL_GET_SECTION_NAME = \ { \ .open = '[', .close = ']', \ .forceclose = 1, .forceskip = 1, \ .skip = " \t\r", .skiplen = 3, \ .inner.debug = "get_section_name" } ; /********************************** * parser split function * *******************************/ int section_get_range(section_t *sasection,stralloc *src) { if (!src->len) return 0 ; size_t pos = 0, start = 0 ; int r, n = 0, id = -1, skip = 0 ; stralloc secname = STRALLOC_ZERO ; stralloc_ref psasection ; stralloc cp = STRALLOC_ZERO ; /** be clean */ wild_zero_all(&MILL_GET_LINE) ; wild_zero_all(&MILL_GET_SECTION_NAME) ; r = mill_string(&cp,src,&MILL_GET_LINE) ; if (r == -1 || !r) goto err ; if (!sastr_rebuild_in_nline(&cp) || !stralloc_0(&cp)) goto err ; while (pos < cp.len) { if(secname.len && n) { skip = section_get_skip(cp.s,pos,MILL_GET_SECTION_NAME.inner.nline) ; id = get_enumbyid(secname.s,key_enum_section_el) ; section_setsa(id,&psasection,sasection) ; if (skip) sasection->idx[id] = 1 ; } if (!section_get_id(&secname,cp.s,&pos,&id)) goto err ; if (!secname.len && !n) goto err ; if (!n) { skip = section_get_skip(cp.s,pos,MILL_GET_SECTION_NAME.inner.nline) ; section_setsa(id,&psasection,sasection) ; if (skip) sasection->idx[id] = 1 ; start = pos ; if (!section_get_id(&secname,cp.s,&pos,&id)) goto err ; if(skip) { r = get_rlen_until(cp.s,'\n',pos-1) ;//-1 to retrieve the end of previous line if (r == -1) goto err ; if (!stralloc_catb(psasection,cp.s+start,(r-start))) goto err ; if (!stralloc_0(psasection)) goto err ; } n++ ; start = pos ; } else { if (skip) { /** end of file do not contain section, avoid to remove the len of it if in the case*/ if (secname.len) { r = get_rlen_until(cp.s,'\n',pos-1) ;//-1 to retrieve the end of previous line if (r == -1) goto err ; if (!stralloc_catb(psasection,cp.s+start,(r - start))) goto err ; } else if (!stralloc_catb(psasection,cp.s+start,cp.len - start)) goto err ; if (!stralloc_0(psasection)) goto err ; } start = pos ; } } stralloc_free(&secname) ; stralloc_free(&cp) ; return 1 ; err: stralloc_free(&secname) ; stralloc_free(&cp) ; return 0 ; } int key_get_range(genalloc *ga, section_t *sasection,int *svtype) { int r ; size_t pos = 0, fakepos = 0 ; uint8_t found = 0 ; stralloc sakey = STRALLOC_ZERO ; stralloc_ref psasection ; key_all_t const *list = total_list ; for (int i = 0 ; i < key_enum_section_el ; i++) { if (sasection->idx[i]) { if (i == ENV) { pos = 0 ; keynocheck nocheck = KEYNOCHECK_ZERO ; nocheck.idsec = i ; nocheck.idkey = ENVAL ; nocheck.expected = KEYVAL ; nocheck.mandatory = OPTS ; section_setsa(i,&psasection,sasection) ; if (!stralloc_cats(&nocheck.val,psasection->s+1)) goto err ;//+1 remove the first '\n' if (!environ_get_clean_env(&nocheck.val)) { log_warnu("parse section: ",get_keybyid(i)) ; goto err ; } if (!stralloc_cats(&nocheck.val,"\n") || !stralloc_0(&nocheck.val)) goto err ; nocheck.val.len-- ; if (!genalloc_append(keynocheck,ga,&nocheck)) goto err ; } else { section_setsa(i,&psasection,sasection) ; pos = 0 ; size_t blen = psasection->len ; while (pos < blen) { keynocheck nocheck = KEYNOCHECK_ZERO ; sakey.len = 0 ; r = mill_element(&sakey,psasection->s,&MILL_GET_AROBASE_KEY,&pos) ; if (r == -1) goto err ; if (!r) break ; //end of string fakepos = get_rlen_until(psasection->s,'\n',pos) ; r = mill_element(&sakey,psasection->s,&MILL_GET_COMMENTED_KEY,&fakepos) ; if (r == -1) goto err ; if (r) continue ; if (!stralloc_cats(&nocheck.val,psasection->s+pos)) goto err ; if (!stralloc_0(&nocheck.val)) goto err ; for (int j = 0 ; j < total_list_el[i]; j++) { found = 0 ; if (list[i].list[j].name && obstr_equal(sakey.s,list[i].list[j].name)) { nocheck.idsec = i ; nocheck.idkey = get_enumbyid(sakey.s,key_enum_el) ; nocheck.expected = list[i].list[j].expected ; nocheck.mandatory = list[i].list[j].mandatory ; found = 1 ; switch(list[i].list[j].expected) { case QUOTE: if (!sastr_get_double_quote(&nocheck.val)) { parse_err(6,&nocheck) ; goto err ; } if (!stralloc_0(&nocheck.val)) goto err ; break ; case BRACKET: if (!parse_bracket(&nocheck.val,&pos)) { parse_err(6,&nocheck) ; goto err ; } if (nocheck.val.len == 1) { parse_err(9,&nocheck) ; goto err ; } break ; case LINE: case UINT: case SLASH: if (!parse_line(&nocheck.val,&pos)) { parse_err(7,&nocheck) ; goto err ; } if (nocheck.val.len == 1) { parse_err(9,&nocheck) ; goto err ; } if (!i && !j) (*svtype) = get_enumbyid(nocheck.val.s,key_enum_el) ; break ; default: return 0 ; } if (!genalloc_append(keynocheck,ga,&nocheck)) goto err ; break ; } } if (!found && r >=0) { log_warn("unknown key: ",sakey.s," : in section: ",get_keybyid(sasection->idx[i])) ; keynocheck_free(&nocheck) ; goto err ; } } } } } stralloc_free(&sakey) ; return 1 ; err: stralloc_free(&sakey) ; return 0 ; } int get_mandatory(genalloc *nocheck,int idsec,int idkey) { int count, bkey, r, countidsec ; key_all_t const *list = total_list ; stralloc sa = STRALLOC_ZERO ; r = -1 ; count = 0 ; bkey = -1 ; countidsec = 0 ; switch(list[idsec].list[idkey].mandatory){ case NEED: for (unsigned int j = 0;j < genalloc_len(keynocheck,nocheck);j++) { if (genalloc_s(keynocheck,nocheck)[j].idsec == idsec) { countidsec++ ; if (genalloc_s(keynocheck,nocheck)[j].idkey == get_enumbyid(list[idsec].list[idkey].name,key_enum_el)) { count++ ; break ; } } } if ((!count) && (countidsec)) log_warn_return(LOG_EXIT_ZERO,"mandatory key: ",list[idsec].list[idkey].name," not found on section: ",get_keybyid(idsec)) ; break ; case CUSTOM: for (unsigned int j = 0;j < genalloc_len(keynocheck,nocheck);j++) { if (genalloc_s(keynocheck,nocheck)[j].idsec == idsec) { countidsec++ ; if (genalloc_s(keynocheck,nocheck)[j].idkey == BUILD) { bkey = j ; } if (genalloc_s(keynocheck,nocheck)[j].idkey == get_enumbyid(list[idsec].list[idkey].name,key_enum_el)) { count++ ; break ; } } } if ((!count) && (countidsec) && bkey>=0) { if (obstr_equal(genalloc_s(keynocheck,nocheck)[bkey].val.s,get_keybyid(CUSTOM))) log_warn_return(LOG_EXIT_ZERO,"custom build asked on section: ",get_keybyid(idsec)," -- key: ",list[idsec].list[idkey].name," must be set") ; } break ; case BUNDLE: for (unsigned int j = 0;j < genalloc_len(keynocheck,nocheck);j++) { if (genalloc_s(keynocheck,nocheck)[j].idsec == idsec) { countidsec++ ; if (genalloc_s(keynocheck,nocheck)[j].idkey == TYPE) { bkey = j; } if (genalloc_s(keynocheck,nocheck)[j].idkey == get_enumbyid(list[idsec].list[idkey].name,key_enum_el)) { count++ ; } } } if ((!count) && (countidsec) && bkey>=0) { if (obstr_equal(genalloc_s(keynocheck,nocheck)[bkey].val.s,get_keybyid(BUNDLE))) log_warn_return(LOG_EXIT_ZERO,"bundle type detected -- key @contents must be set") ; } break ; /** only pass through here to check if flags env was asked * and the corresponding section exist*/ case OPTS: for (unsigned int j = 0;j < genalloc_len(keynocheck,nocheck);j++) { if (genalloc_s(keynocheck,nocheck)[j].idsec == ENV) count++ ; if (genalloc_s(keynocheck,nocheck)[j].idsec == MAIN) { if (genalloc_s(keynocheck,nocheck)[j].idkey == OPTIONS) { bkey = j; } } } if (bkey >= 0) { if (!sastr_clean_string(&sa,genalloc_s(keynocheck,nocheck)[bkey].val.s)) log_warnu_return(LOG_EXIT_ZERO,"clean value of: ",sa.s) ; r = sastr_cmp(&sa,get_keybyid(ENVIR)) ; if ((r >= 0) && (!count)) log_warn_return(LOG_EXIT_ZERO,"options env was asked -- section environment must be set") ; } break ; default: break ; } stralloc_free(&sa) ; return 1 ; } int nocheck_toservice(keynocheck *nocheck,int svtype, sv_alltype *service) { static unsigned char const actions[5][4] = { //c->CLASSIC, BUNDLE, LONGRUN, ONESHOT { COMMON, COMMON, COMMON, COMMON }, // main { EXECRUN, SKIP, EXECRUN, EXECUP }, // start { EXECFINISH, SKIP, EXECFINISH, EXECDOWN }, // stop { EXECLOG, SKIP, EXECLOG, SKIP }, // log { ENVIRON, SKIP, ENVIRON, ENVIRON }, // env } ; static unsigned char const states[5][4] = { //c->CLASSIC, BUNDLE, LONGRUN, ONESHOT { START, SKIP, START, START }, // main { STOP, SKIP, STOP, STOP }, // start { LOG, SKIP, LOG, LOG }, // stop { ENV, SKIP, ENV, ENV }, // log { SKIP, SKIP, SKIP, SKIP }, // env } ; int p ; p = svtype ; int state = 0 ; while (state < 6) { unsigned int c = p - CLASSIC; unsigned int action = actions[state][c] ; state = states[state][c] ; switch (action) { case COMMON: if (!nocheck->idsec) if (!keep_common(service,nocheck,svtype)) return 0 ; break ; case EXECRUN: if (nocheck->idsec == 1) if (!keep_runfinish(&service->type.classic_longrun.run,nocheck)) return 0 ; break ; case EXECFINISH: if (nocheck->idsec == 2) if (!keep_runfinish(&service->type.classic_longrun.finish,nocheck)) return 0 ; break ; case EXECLOG: if (nocheck->idsec == 3) if (!keep_logger(&service->type.classic_longrun.log,nocheck)) return 0 ; break ; case EXECUP: if (nocheck->idsec == 1) if (!keep_runfinish(&service->type.oneshot.up,nocheck)) return 0 ; break ; case EXECDOWN: if (nocheck->idsec == 2) if (!keep_runfinish(&service->type.oneshot.down,nocheck)) return 0 ; break ; case ENVIRON: if (nocheck->idsec == 4) if (!keep_common(service,nocheck,svtype)) return 0 ; break ; case SKIP: break ; default: log_warn_return(LOG_EXIT_ZERO,"unknown action") ; } } return 1 ; } /********************************** * store * *******************************/ int keep_common(sv_alltype *service,keynocheck *nocheck,int svtype) { int r = 0 ; size_t pos = 0, *chlen = &nocheck->val.len ; char *chval = nocheck->val.s ; switch(nocheck->idkey){ case TYPE: r = get_enum(chval,nocheck) ; if (!r) return 0 ; service->cname.itype = r ; break ; case NAME: service->cname.name = keep.len ; if (!stralloc_catb(&keep,chval,*chlen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; break ; case DESCRIPTION: service->cname.description = keep.len ; if (!stralloc_catb(&keep,chval,*chlen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; break ; case OPTIONS: if (!get_clean_val(nocheck)) return 0 ; for (;pos < *chlen; pos += strlen(chval + pos)+1) { r = get_enum(chval + pos,nocheck) ; if (!r) return 0 ; if (svtype == CLASSIC || svtype == LONGRUN) { if (r == LOGGER) service->opts[0] = 1 ;/**0 means not enabled*/ else if (svtype == LONGRUN && r == PIPELINE) service->opts[1] = 1 ; } if (r == ENVIR) service->opts[2] = 1 ; } break ; case FLAGS: if (!get_clean_val(nocheck)) return 0 ; for (;pos < *chlen; pos += strlen(chval + pos)+1) { r = get_enum(chval + pos,nocheck) ; if (!r) return 0 ; if (r == DOWN) service->flags[0] = 1 ;/**0 means not enabled*/ if (r == NOSETSID) service->flags[1] = 1 ; } break ; case USER: if (!get_clean_val(nocheck)) return 0 ; { uid_t owner = MYUID ; if (!owner) { if (sastr_find(&nocheck->val,"root") == -1) log_warnu_return(LOG_EXIT_ZERO,"use service: ",keep.s+service->cname.name," -- permission denied") ; } /** special case, we don't know which user want to use * the service, we need a general name to allow all user * the term "user" is took here to allow the current user*/ ssize_t p = sastr_cmp(&nocheck->val,"user") ; for (;pos < *chlen; pos += strlen(chval + pos)+1) { if (pos == (size_t)p) continue ; if (!scan_uidlist(chval + pos,(uid_t *)service->user)) { parse_err(0,nocheck) ; return 0 ; } } uid_t nb = service->user[0] ; if (p == -1 && owner) { int e = 0 ; for (int i = 1; i < nb+1; i++) if (service->user[i] == owner) e = 1 ; if (!e) log_warnu_return(LOG_EXIT_ZERO,"use service: ",keep.s+service->cname.name," -- permission denied") ; } } break ; case HIERCOPY: if (!get_clean_val(nocheck)) return 0 ; { unsigned int idx = 0 ; for (;pos < *chlen; pos += strlen(chval + pos)+1) { char *name = chval + pos ; size_t namelen = strlen(chval + pos) ; service->hiercopy[idx+1] = keep.len ; if (!stralloc_catb(&keep,name,namelen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; service->hiercopy[0] = ++idx ; } } break ; case DEPENDS: if ((service->cname.itype == CLASSIC) || (service->cname.itype == BUNDLE)) log_warn_return(LOG_EXIT_ZERO,"key: ",get_keybyid(nocheck->idkey),": is not valid for type ",get_keybyid(service->cname.itype)) ; if (!get_clean_val(nocheck)) return 0 ; service->cname.idga = deps.len ; for (;pos < *chlen; pos += strlen(chval + pos)+1) { if (!stralloc_catb(&deps,chval + pos,strlen(chval + pos) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; service->cname.nga++ ; } break ; case CONTENTS: if (service->cname.itype != BUNDLE) log_warn_return(LOG_EXIT_ZERO,"key: ",get_keybyid(nocheck->idkey),": is not valid for type ",get_keybyid(service->cname.itype)) ; if (!get_clean_val(nocheck)) return 0 ; service->cname.idga = deps.len ; for (;pos < *chlen; pos += strlen(chval + pos) + 1) { if (!stralloc_catb(&deps,chval + pos,strlen(chval + pos) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; service->cname.nga++ ; } break ; case T_KILL: case T_FINISH: case T_UP: case T_DOWN: if (!get_timeout(nocheck,(uint32_t *)service->timeout)) return 0 ; break ; case DEATH: if (!get_uint(nocheck,&service->death)) return 0 ; break ; case NOTIFY: if (!get_uint(nocheck,&service->notification)) return 0 ; break ; case ENVAL: if (!environ_clean_nline(&nocheck->val)) log_warnu_return(LOG_EXIT_ZERO,"clean environment value: ",chval) ; if (!stralloc_cats(&nocheck->val,"\n")) return 0 ; if (!stralloc_copy(&service->saenv,&nocheck->val)) log_warnu_return(LOG_EXIT_ZERO,"store environment value: ",chval) ; break ; case SIGNAL: if (!sig0_scan(chval,&service->signal)) { parse_err(3,nocheck) ; return 0 ; } break ; default: log_warn_return(LOG_EXIT_ZERO,"unknown key: ",get_keybyid(nocheck->idkey)) ; } return 1 ; } int keep_runfinish(sv_exec *exec,keynocheck *nocheck) { int r = 0 ; size_t *chlen = &nocheck->val.len ; char *chval = nocheck->val.s ; switch(nocheck->idkey) { case BUILD: r = get_enum(chval,nocheck) ; if (!r) return 0 ; exec->build = r ; break ; case RUNAS: if (!check_valid_runas(nocheck)) return 0 ; exec->runas = keep.len ; if (!stralloc_catb(&keep,chval,*chlen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; break ; case SHEBANG: if (chval[0] != '/') { parse_err(4,nocheck) ; return 0 ; } exec->shebang = keep.len ; if (!stralloc_catb(&keep,chval,*chlen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; break ; case EXEC: exec->exec = keep.len ; if (!stralloc_catb(&keep,chval,*chlen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; break ; default: log_warn_return(LOG_EXIT_ZERO,"unknown key: ",get_keybyid(nocheck->idkey)) ; } return 1 ; } int keep_logger(sv_execlog *log,keynocheck *nocheck) { int r ; size_t pos = 0, *chlen = &nocheck->val.len ; char *chval = nocheck->val.s ; switch(nocheck->idkey){ case BUILD: if (!keep_runfinish(&log->run,nocheck)) return 0 ; break ; case RUNAS: if (!keep_runfinish(&log->run,nocheck)) return 0 ; break ; case DEPENDS: if (!get_clean_val(nocheck)) return 0 ; log->idga = deps.len ; for (;pos < *chlen; pos += strlen(chval + pos) + 1) { if (!stralloc_catb(&deps,chval + pos,strlen(chval + pos) + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; log->nga++ ; } break ; case SHEBANG: if (!keep_runfinish(&log->run,nocheck)) return 0 ; break ; case EXEC: if (!keep_runfinish(&log->run,nocheck)) return 0 ; break ; case T_KILL: case T_FINISH: if (!get_timeout(nocheck,(uint32_t *)log->timeout)) return 0 ; break ; case DESTINATION: if (chval[0] != '/') { parse_err(4,nocheck) ; return 0 ; } log->destination = keep.len ; if (!stralloc_catb(&keep,chval,*chlen + 1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; break ; case BACKUP: if (!get_uint(nocheck,&log->backup)) return 0 ; break ; case MAXSIZE: if (!get_uint(nocheck,&log->maxsize)) return 0 ; break ; case TIMESTP: r = get_enum(chval,nocheck) ; if (!r) return 0 ; log->timestamp = r ; break ; default: log_warn_return(LOG_EXIT_ZERO,"unknown key: ",get_keybyid(nocheck->idkey)) ; } return 1 ; } /********************************** * helper function * *******************************/ int read_svfile(stralloc *sasv,char const *name,char const *src) { int r ; size_t srclen = strlen(src) ; size_t namelen = strlen(name) ; char svtmp[srclen + 1 + namelen + 1] ; memcpy(svtmp,src,srclen) ; svtmp[srclen] = '/' ; memcpy(svtmp + srclen + 1, name, namelen) ; svtmp[srclen + 1 + namelen] = 0 ; log_trace("Read service file of : ",name," from: ",src) ; size_t filesize=file_get_size(svtmp) ; if (!filesize) log_warn_return(LOG_EXIT_ZERO,svtmp," is empty") ; r = openreadfileclose(svtmp,sasv,filesize) ; if(!r) log_warnusys_return(LOG_EXIT_ZERO,"open ", svtmp) ; /** ensure that we have an empty line at the end of the string*/ if (!stralloc_cats(sasv,"\n")) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(sasv)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; return 1 ; } int add_pipe(sv_alltype *sv, stralloc *sa) { char *prodname = keep.s+sv->cname.name ; stralloc tmp = STRALLOC_ZERO ; sv->pipeline = sa->len ; if (!stralloc_cats(&tmp,SS_PIPE_NAME)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_cats(&tmp,prodname)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_0(&tmp)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; if (!stralloc_catb(sa,tmp.s,tmp.len+1)) log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; stralloc_free(&tmp) ; return 1 ; } int parse_line(stralloc *sa, size_t *pos) { if (!sa->len) return 0 ; int r = 0 ; size_t newpos = 0 ; stralloc kp = STRALLOC_ZERO ; wild_zero_all(&MILL_CLEAN_LINE) ; r = mill_element(&kp,sa->s,&MILL_CLEAN_LINE,&newpos) ; if (r == -1 || !r) goto err ; if (!stralloc_0(&kp)) goto err ; if (!stralloc_copy(sa,&kp)) goto err ; *pos += newpos - 1 ; stralloc_free(&kp) ; return 1 ; err: stralloc_free(&kp) ; return 0 ; } int parse_bracket(stralloc *sa,size_t *pos) { if (!sa->len) return 0 ; size_t newpos = 0 ; stralloc kp = STRALLOC_ZERO ; if (!key_get_next_id(&kp,sa->s,&newpos)) goto err ; if (!stralloc_0(&kp)) goto err ; if (!stralloc_copy(sa,&kp)) goto err ; *pos += newpos ; stralloc_free(&kp) ; return 1 ; err: stralloc_free(&kp) ; return 0 ; } void section_setsa(int id, stralloc_ref *p,section_t *sa) { switch(id) { case MAIN: *p = &sa->main ; break ; case START: *p = &sa->start ; break ; case STOP: *p = &sa->stop ; break ; case LOG: *p = &sa->logger ; break ; case ENV: *p = &sa->environment ; break ; default: break ; } } int section_get_skip(char const *s,size_t pos,int nline) { ssize_t r = -1 ; if (nline == 1) { r = get_sep_before(s,'#','[') ; if (r >= 0) return 0 ; } r = get_rlen_until(s,'\n',pos) ; if (r >= 0) { r = get_sep_before(s+r+1,'#','[') ; if (r >= 0) return 0 ; } return 1 ; } int section_get_id(stralloc *secname, char const *string,size_t *pos,int *id) { size_t len = strlen(string) ; size_t newpos = 0 ; (*id) = -1 ; while ((*id) < 0 && (*pos) < len) { secname->len = 0 ; newpos = 0 ; if (mill_element(secname,string+(*pos),&MILL_GET_SECTION_NAME,&newpos) == -1) return 0 ; if (secname->len) { if (!stralloc_0(secname)) return 0 ; (*id) = get_enumbyid(secname->s,key_enum_section_el) ; } (*pos) += newpos ; } return 1 ; } int key_get_next_id(stralloc *sa, char const *string,size_t *pos) { if (!string) return 0 ; int r = 0 ; size_t newpos = 0, len = strlen(string) ; stralloc kp = STRALLOC_ZERO ; wild_zero_all(&MILL_GET_AROBASE_KEY) ; wild_zero_all(&MILL_FIRST_BRACKET) ; int id = -1 ; r = mill_element(&kp,string,&MILL_FIRST_BRACKET,&newpos) ; if (r == -1 || !r) goto err ; *pos = newpos ; while (id == -1 && newpos < len) { kp.len = 0 ; r = mill_element(&kp,string,&MILL_GET_AROBASE_KEY,&newpos) ; if (r == -1) goto err ; if (!stralloc_0(&kp)) goto err ; id = get_enumbyid(kp.s,key_enum_el) ; if (id == -1 && kp.len > 1) log_warn("unknown key: ",kp.s,": at parenthesis parse") ; } newpos = get_rlen_until(string,')',newpos) ; if (newpos == -1) goto err ; if (!stralloc_catb(sa,string+*pos,newpos - *pos)) goto err ; *pos = newpos + 1 ; //+1 remove the last ')' stralloc_free(&kp) ; return 1 ; err: stralloc_free(&kp) ; return 0 ; } int get_clean_val(keynocheck *ch) { if (!sastr_clean_element(&ch->val)) { parse_err(8,ch) ; return 0 ; } return 1 ; } int get_enum(char const *string, keynocheck *ch) { int r = get_enumbyid(string,key_enum_el) ; if (r == -1) { parse_err(0,ch) ; return 0 ; } return r ; } int get_timeout(keynocheck *ch,uint32_t *ui) { int time = 0 ; if (ch->idkey == T_KILL) time = 0 ; else if (ch->idkey == T_FINISH) time = 1 ; else if (ch->idkey == T_UP) time = 2 ; else if (ch->idkey == T_DOWN) time = 3 ; if (scan_timeout(ch->val.s,ui,time) == -1) { parse_err(3,ch) ; return 0 ; } return 1 ; } int get_uint(keynocheck *ch,uint32_t *ui) { if (!uint32_scan(ch->val.s,ui)) { parse_err(3,ch) ; return 0 ; } return 1 ; } int check_valid_runas(keynocheck *ch) { errno = 0 ; struct passwd *pw = getpwnam(ch->val.s); if (pw == NULL && errno) { parse_err(0,ch) ; return 0 ; } return 1 ; } void parse_err(int ierr,keynocheck *check) { int idsec = check->idsec ; int idkey = check->idkey ; switch(ierr) { case 0: log_warn("invalid value for key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; case 1: log_warn("multiple definition of key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; case 2: log_warn("same value for key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; case 3: log_warn("key: ",get_keybyid(idkey),": must be an integrer value in section: ",get_keybyid(idsec)) ; break ; case 4: log_warn("key: ",get_keybyid(idkey),": must be an absolute path in section: ",get_keybyid(idsec)) ; break ; case 5: log_warn("key: ",get_keybyid(idkey),": must be set in section: ",get_keybyid(idsec)) ; break ; case 6: log_warn("invalid format of key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; case 7: log_warnu("parse key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; case 8: log_warnu("clean value of key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; case 9: log_warn("empty value of key: ",get_keybyid(idkey),": in section: ",get_keybyid(idsec)) ; break ; default: log_warn("unknown parse_err number") ; break ; } }