/* * 66-envfile.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 <string.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> #include <oblibs/string.h> #include <oblibs/stralist.h> #include <oblibs/error2.h> #include <oblibs/obgetopt.h> #include <oblibs/directory.h> #include <oblibs/files.h> #include <skalibs/bytestr.h> #include <skalibs/stralloc.h> #include <skalibs/genalloc.h> #include <skalibs/env.h> #include <skalibs/djbunix.h> #include <skalibs/diuint32.h> #include <skalibs/env.h> #include <skalibs/sgetopt.h> #include <execline/execline.h> #include <66/parser.h> unsigned int VERBOSITY = 1 ; static stralloc senv = STRALLOC_ZERO ; static genalloc gaenv = GENALLOC_ZERO ; //diuint32, pos in senv static int MAXVAR = 100 ; static int MAXFILE = 500 ; #define USAGE "66-envfile [ -h help ] [ -f file ] [ -l ] dir prog" typedef struct exlsn_s exlsn_t, *exlsn_t_ref ; struct exlsn_s { stralloc vars ; stralloc values ; genalloc data ; // array of elsubst stralloc modifs ; } ; #define EXLSN_ZERO { .vars = STRALLOC_ZERO, .values = STRALLOC_ZERO, .data = GENALLOC_ZERO, .modifs = STRALLOC_ZERO } static inline void info_help (void) { static char const *help = "66-envfile <options> dir prog\n" "\n" "options :\n" " -h: print this help\n" " -f: file to parse\n" " -l: loose\n" ; if (buffer_putsflush(buffer_1, help) < 0) strerr_diefu1sys(111, "write to stdout") ; } static int env_substitute(char const *key, char const *val,exlsn_t *info, char const *const *envp,int unexport) { char const *defaultval = "" ; char const *x ; int insist = 0 ; eltransforminfo_t si = ELTRANSFORMINFO_ZERO ; elsubst_t blah ; blah.var = info->vars.len ; blah.value = info->values.len ; if (el_vardupl(key, info->vars.s, info->vars.len)) strerr_dief1x(111, "bad substitution key") ; if (!stralloc_catb(&info->vars,key, strlen(key) + 1)) retstralloc(111,"env_substitute") ; x = env_get2(envp, key) ; if (!x) { if (insist) strerr_dief2x(111, val,": is not set") ; x = defaultval ; } else if (unexport) { if (!stralloc_catb(&info->modifs, key, strlen(key) + 1)) goto err ; } if (!x) blah.n = 0 ; else { int r ; if (!stralloc_cats(&info->values, x)) goto err ; r = el_transform(&info->values, blah.value, &si) ; if (r < 0) goto err ; blah.n = r ; } if (!genalloc_append(elsubst_t, &info->data, &blah)) goto err ; return 1 ; err: info->vars.len = blah.var ; info->values.len = blah.value ; strerr_diefu1x(111,"complete environment substition") ; } int new_env(char const *path,char const *file,stralloc *modifs) { int nbline = 0, i = 0 ; stralloc sa = STRALLOC_ZERO ; genalloc gatmp = GENALLOC_ZERO ;//stralist if (!file_readputsa(&sa,path,file)) strerr_diefu4sys(111,"read file: ",path,"/",file) ; if (!parse_env(&sa)) strerr_dief2x(111,"parse file: ", file) ; nbline = get_nbline_ga(sa.s,sa.len,&gatmp) ; for (i = 0;i < nbline;i++) if (!add_env(gaistr(&gatmp,i),&gaenv,&senv)) strerr_diefu2x(111,"append genalloc with: ",gaistr(&gatmp,i)) ; for (i = 0 ; i < genalloc_len(diuint32,&gaenv) ; i++) { if (i > MAXVAR) strerr_dief4x(111,"to many variable in file: ",path,"/",file) ; int key = genalloc_s(diuint32,&gaenv)[i].left ; int val = genalloc_s(diuint32,&gaenv)[i].right ; if ((senv.s+key)[0] == '!') key++; if (!env_addmodif(modifs,senv.s + key,senv.s + val)) strerr_diefu1x(111,"add environment") ; } genalloc_deepfree(stralist,&gatmp,stra_free) ; return 1 ; } int main (int argc, char const *const *argv, char const *const *envp) { int r, i, one, unexport ; int insist = 1 ; char const *path = 0 ; char const *file = 0 ; stralloc modifs = STRALLOC_ZERO ; stralloc dst = STRALLOC_ZERO ; genalloc toparse = GENALLOC_ZERO ; //stralist exlsn_t info = EXLSN_ZERO ; r = i = one = unexport = 0 ; insist = 1 ; PROG = "66-envfile" ; { subgetopt_t l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc,argv, ">hlf:", &l) ; if (opt == -1) break ; if (opt == -2) strerr_dief1x(110,"options must be set first") ; switch (opt) { case 'h' : info_help(); return 0 ; case 'f' : file = l.arg ; one = 1 ; break ; case 'l' : insist = 0 ; break ; default : exitusage(USAGE) ; } } argc -= l.ind ; argv += l.ind ; } if (argc < 2) exitusage(USAGE) ; path = *argv ; if (path[0] != '/') strerr_dief3x(111,"directory: ",path," must be an absolute path") ; r = dir_get(&toparse,path,"",S_IFREG) ; if (!r && insist) strerr_diefu2sys(111,"get file from: ",path) ; else if ((!r && !insist) || !genalloc_len(stralist,&toparse)) { argv++; argc--; xpathexec_run(argv[0],argv,envp) ; } if (one) { r = stra_findidx(&toparse,file) ; if (r < 0) { if (insist) strerr_diefu2x(111,"find: ",file) ; else { argv++; argc--; xpathexec_run(argv[0],argv,envp) ; } } new_env(path,file,&modifs) ; } else { for (i = 0 ; i < genalloc_len(stralist,&toparse) ; i++) { if (i > MAXFILE) strerr_dief2x(111,"to many file to parse in: ",path) ; new_env(path,gaistr(&toparse,i),&modifs) ; } } genalloc_deepfree(stralist,&toparse,stra_free) ; size_t n = env_len(envp) + 1 + byte_count(modifs.s,modifs.len,'\0') ; char const *newenv[n] ; if (!env_merge (newenv, n ,envp,env_len(envp),modifs.s, modifs.len)) strerr_diefu1sys(111,"build environment") ; modifs.len = 0 ; for (i = 0 ; i < genalloc_len(diuint32,&gaenv) ; i++) { unexport = 0 ; int key = genalloc_s(diuint32,&gaenv)[i].left ; int val = genalloc_s(diuint32,&gaenv)[i].right ; if ((senv.s+key)[0] == '!') { key++ ; unexport = 1 ; } env_substitute(senv.s + key,senv.s + val,&info,newenv,unexport) ; } genalloc_free(diuint32,&gaenv) ; stralloc_free(&senv) ; argv++; argc--; if (!env_string (&modifs, argv, (unsigned int) argc)) strerr_diefu1x(111,"make environment string") ; r = el_substitute (&dst, modifs.s, modifs.len, info.vars.s, info.values.s, genalloc_s (elsubst_t const, &info.data),genalloc_len (elsubst_t const, &info.data)) ; if (r < 0) strerr_diefu1sys(111,"el_substitute") ; else if (!r) _exit(0) ; stralloc_free(&modifs) ; { char const *v[r + 1] ; if (!env_make (v, r ,dst.s, dst.len)) strerr_diefu1sys(111,"make environment") ; v[r] = 0 ; pathexec_r (v, newenv, env_len(newenv),info.modifs.s,info.modifs.len) ; } }