diff --git a/src/include/66/environ.h b/src/include/66/environ.h index 6d2ed0232ad8117ca6e35c0d75f2a8a04ad84152..94cef19b8d93f208a9c78299ddc4d6102f9584bc 100644 --- a/src/include/66/environ.h +++ b/src/include/66/environ.h @@ -20,6 +20,8 @@ #include <skalibs/stralloc.h> extern int env_resolve_conf(stralloc *env,uid_t owner) ; -extern int env_merge_conf(char const *dst,char const *file,stralloc *srclist,stralloc *modifs,unsigned int force) ; +extern int env_merge_conf(stralloc *result,stralloc *srclist,stralloc *modifs,uint8_t conf) ; +extern int env_clean_with_comment(stralloc *sa) ; +extern int env_compute(stralloc *result,sv_alltype *sv, uint8_t conf) ; #endif diff --git a/src/lib66/environ.c b/src/lib66/environ.c index 4ff1f52665e24af8698c8d7bd9943e8b8f684ed5..8a3c5f3b9fadb98acd0ba1fc6457d877136623b7 100644 --- a/src/lib66/environ.c +++ b/src/lib66/environ.c @@ -12,19 +12,21 @@ * except according to the terms contained in the LICENSE file./ */ -//#include <stdio.h> #include <sys/types.h> #include <string.h> +//#include <stdio.h> #include <oblibs/environ.h> #include <oblibs/sastr.h> #include <oblibs/files.h> #include <oblibs/string.h> +#include <oblibs/types.h> #include <skalibs/stralloc.h> #include <66/constants.h> #include <66/utils.h> +#include <66/environ.h> int env_resolve_conf(stralloc *env, uid_t owner) { @@ -42,89 +44,195 @@ int env_resolve_conf(stralloc *env, uid_t owner) return 1 ; } -int env_merge_conf(char const *dst,char const *file,stralloc *srclist,stralloc *modifs,unsigned int force) +int env_merge_conf(stralloc *result,stralloc *srclist,stralloc *modifs,uint8_t conf) { - int r ; - size_t pos = 0, fakepos = 0 ; - stralloc result = STRALLOC_ZERO ; - stralloc sval = STRALLOC_ZERO ; - stralloc mkey = STRALLOC_ZERO ; - stralloc mval = STRALLOC_ZERO ; - - if (!environ_get_clean_env(srclist) || - !environ_clean_nline(srclist) || - !stralloc_0(srclist)) goto err ; - srclist->len-- ; - - - if (!environ_get_clean_env(modifs) || - !environ_clean_nline(modifs) || - !stralloc_0(modifs)) goto err ; - modifs->len-- ; + int r, comment ; + size_t pos = 0 ; + char *end = 0 ; + stralloc user = STRALLOC_ZERO ; + stralloc key = STRALLOC_ZERO ; + stralloc val = STRALLOC_ZERO ; - if (!stralloc_copy(&result,srclist) || - !sastr_split_string_in_nline(modifs) || + if (!auto_stra(&user,"\n## diff from upstream ##\n")) goto err ; + + /** User can empty the file and the function + * fail. In that case we rewrite the file entirely */ + if (!env_clean_with_comment(srclist)) { + if (!auto_stra(result,modifs->s)) goto err ; + goto freed ; + } + + if (!env_clean_with_comment(modifs)) goto err ; + + if (!sastr_split_string_in_nline(modifs) || !sastr_split_string_in_nline(srclist)) goto err ; - - if (!stralloc_0(&result)) goto err ; - result.len-- ; - + for (;pos < modifs->len; pos += strlen(modifs->s + pos) + 1) { - - fakepos = pos ; - sval.len = mkey.len = mval.len = 0 ; - - if (!stralloc_copy(&mkey,modifs) || - !stralloc_copy(&mval,modifs) || - !stralloc_copy(&sval,srclist)) goto err ; - - if (!environ_get_key_nclean(&mkey,&pos)) goto err ; - mkey.len-- ; - - if (!auto_stra(&mkey,"=")) goto err ; - r = sastr_find(srclist,mkey.s) ; + comment = modifs->s[pos] == '#' ? 1 : 0 ; + key.len = 0 ; + char *line = modifs->s + pos ; + + /** keep a empty line between key=value pair and a comment */ + end = get_len_until(line,'=') < 0 ? "\n" : "\n\n" ; + + if (comment) + { + if (!auto_stra(result,line,end)) goto err ; + continue ; + } + if (!stralloc_copy(&key,modifs)) goto err ; + if (!environ_get_key_nclean(&key,&pos)) goto err ; + key.len-- ; + if (!auto_stra(&key,"=")) goto err ; + r = sastr_find(srclist,key.s) ; if (r >= 0) { - if (force) + /** apply change from upstream */ + if (conf > 1) { - if (!environ_get_val_of_key(&sval,mkey.s)) goto err ;// || - if (!environ_get_val_of_key(&mval,mkey.s)) goto err ; - //remove 0 - sval.len-- ; - mval.len-- ; - r = sastr_find(&result,mkey.s) ; - char tmp[result.len + 1] ; - auto_strings(tmp,result.s) ; - size_t mlen = r + mkey.len + (mval.len < sval.len ? mval.len : sval.len) ; - size_t add = sval.len > mval.len ? (sval.len - mval.len) : 0 ; - result.len = r + mkey.len ; - stralloc_0(&result) ; - result.len-- ; - if (!auto_stra(&result,mval.s,tmp + mlen + add)) goto err ; + if (!auto_stra(result,"\n",line,"\n\n")) goto err ; + continue ; } - continue ; + /** keep user change */ + else + { + if (!stralloc_copy(&val,srclist)) goto err ; + if (!environ_get_val_of_key(&val,key.s)) goto err ; + if (!auto_stra(result,"\n",key.s,val.s,"\n\n")) goto err ; + continue ; + } + } + + if (!auto_stra(result,"\n",line,end)) goto err ; + } + /** search for a key added by user */ + for (pos = 0 ; pos < srclist->len ; pos += strlen(srclist->s + pos) + 1) + { + comment = srclist->s[pos] == '#' ? 1 : 0 ; + key.len = 0 ; + char *line = srclist->s + pos ; + + if (comment) continue ; + + if (!stralloc_copy(&key,srclist)) goto err ; + if (!environ_get_key_nclean(&key,&pos)) goto err ; + key.len-- ; + if (!auto_stra(&key,"=")) goto err ; + r = sastr_find(modifs,key.s) ; + if (r >= 0) continue ; + + if (!auto_stra(&user,line,"\n")) goto err ; + } + + if (user.len > 26) + if (!auto_stra(result,user.s)) goto err ; + + freed: + + stralloc_free(&user) ; + stralloc_free(&key) ; + stralloc_free(&val) ; + return 1 ; + err: + stralloc_free(&user) ; + stralloc_free(&key) ; + stralloc_free(&val) ; + return 0 ; +} +/* @Return 0 on crash + * @Return 1 if no need to write + * @Return 2 if need to write + * it appends @result with the user file if + * conf = 0 otherwise it appends @result with + * the upstream file modified by env_merge_conf function*/ +int env_compute(stralloc *result,sv_alltype *sv, uint8_t conf) +{ + int r, write = 1 ; + size_t newlen = 0 ; + char *name = keep.s + sv->cname.name ; + stralloc dst = STRALLOC_ZERO ; + stralloc salist = STRALLOC_ZERO ; + + if (!env_resolve_conf(&dst,MYUID)) + log_warnu_return(LOG_EXIT_ZERO,"resolve source of configuration file") ; + + newlen = dst.len ; + if (!auto_stra(&dst,name)) + log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; + + r = scan_mode(dst.s,S_IFREG) ; + if (!r || conf > 2) + { + // copy config file from upstream in sysadmin + if (!stralloc_copy(result,&sv->saenv)) + log_warnsys_return(LOG_EXIT_ZERO,"stralloc") ; + write = 2 ; + goto freed ; + } + else if (conf > 0) + { + dst.s[newlen] = 0 ; + if (!file_readputsa(&salist,dst.s,name)) + log_warnusys_return(LOG_EXIT_ZERO,"read: ",dst.s,name) ; + + //merge config from upstream to sysadmin + if (!env_merge_conf(result,&salist,&sv->saenv,conf)) + log_warnu_return(LOG_EXIT_ZERO,"merge environment file") ; + write = 2 ; + goto freed ; + } + dst.s[newlen] = 0 ; + if (!file_readputsa(result,dst.s,name)) + log_warnusys_return(LOG_EXIT_ZERO,"read: ",dst.s,name) ; + + freed: + stralloc_free(&dst) ; + stralloc_free(&salist) ; + + return write ; +} + +int env_clean_with_comment(stralloc *sa) +{ + ssize_t pos = 0, r ; + char *end = 0, *start = 0 ; + stralloc final = STRALLOC_ZERO ; + stralloc tmp = STRALLOC_ZERO ; + + if (!sastr_split_string_in_nline(sa)) + log_warnu_return(LOG_EXIT_ZERO,"split environment value") ; + + for (; pos < sa->len ; pos += strlen(sa->s + pos) + 1) + { + tmp.len = 0 ; + if (!sastr_clean_string(&tmp,sa->s + pos)) + log_warnu_return(LOG_EXIT_ZERO,"clean environment string") ; + /** keep a empty line between key=value pair and a comment */ + r = get_len_until(tmp.s,'=') ; + end = r < 0 ? "\n" : "\n\n" ; + start = r < 0 ? "" : "\n" ; + + if (tmp.s[0] == '#') + { + if (!sastr_rebuild_in_oneline(&tmp)) + log_warnu_return(LOG_EXIT_ZERO,"rebuild environment string in one line") ; } else { - if (!stralloc_cats(&result,"\n") || - !stralloc_catb(&result,modifs->s+fakepos,strlen(modifs->s + fakepos))) goto err ; + if (!environ_rebuild_line(&tmp)) + log_warnu_return(LOG_EXIT_ZERO,"rebuild environment line") ; } - + + if (!auto_stra(&final,start,tmp.s,end)) + log_warn_return(LOG_EXIT_ZERO,"append stralloc") ; } - if (!auto_stra(&result,"\n")) goto err ; - - if (!file_write_unsafe(dst,file,result.s,result.len)) goto err ; + sa->len = 0 ; + if (!auto_stra(sa,final.s)) + log_warnu_return(LOG_EXIT_ZERO,"store environment value") ; + + stralloc_free(&tmp) ; + stralloc_free(&final) ; - stralloc_free(&result) ; - stralloc_free(&sval) ; - stralloc_free(&mkey) ; - stralloc_free(&mval) ; return 1 ; - err: - stralloc_free(&result) ; - stralloc_free(&sval) ; - stralloc_free(&mkey) ; - stralloc_free(&mval) ; - return 0 ; }