xref: /netbsd-src/external/bsd/ntp/dist/sntp/libopts/env.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: env.c,v 1.5 2020/05/25 20:47:34 christos Exp $	*/
2 
3 
4 /**
5  * \file environment.c
6  *
7  *  This file contains all of the routines that must be linked into
8  *  an executable to use the generated option processing.  The optional
9  *  routines are in separately compiled modules so that they will not
10  *  necessarily be linked in.
11  *
12  * @addtogroup autoopts
13  * @{
14  */
15 /*
16  *  This file is part of AutoOpts, a companion to AutoGen.
17  *  AutoOpts is free software.
18  *  AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
19  *
20  *  AutoOpts is available under any one of two licenses.  The license
21  *  in use must be one of these two and the choice is under the control
22  *  of the user of the license.
23  *
24  *   The GNU Lesser General Public License, version 3 or later
25  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
26  *
27  *   The Modified Berkeley Software Distribution License
28  *      See the file "COPYING.mbsd"
29  *
30  *  These files have the following sha256 sums:
31  *
32  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
33  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
34  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
35  */
36 
37 /* = = = START-STATIC-FORWARD = = = */
38 static void
39 do_env_opt(tOptState * os, char * env_name,
40             tOptions * pOpts, teEnvPresetType type);
41 /* = = = END-STATIC-FORWARD = = = */
42 
43 /*
44  *  doPrognameEnv - check for preset values from the ${PROGNAME}
45  *  environment variable.  This is accomplished by parsing the text into
46  *  tokens, temporarily replacing the arg vector and calling
47  *  immediate_opts and/or regular_opts.
48  */
49 LOCAL void
50 doPrognameEnv(tOptions * pOpts, teEnvPresetType type)
51 {
52     char const *        env_opts = getenv(pOpts->pzPROGNAME);
53     token_list_t *      pTL;
54     int                 sv_argc;
55     proc_state_mask_t   sv_flag;
56     char **             sv_argv;
57 
58     /*
59      *  No such beast?  Then bail now.
60      */
61     if (env_opts == NULL)
62         return;
63 
64     /*
65      *  Tokenize the string.  If there's nothing of interest, we'll bail
66      *  here immediately.
67      */
68     pTL = ao_string_tokenize(env_opts);
69     if (pTL == NULL)
70         return;
71 
72     /*
73      *  Substitute our $PROGNAME argument list for the real one
74      */
75     sv_argc = (int)pOpts->origArgCt;
76     sv_argv = pOpts->origArgVect;
77     sv_flag = pOpts->fOptSet;
78 
79     /*
80      *  We add a bogus pointer to the start of the list.  The program name
81      *  has already been pulled from "argv", so it won't get dereferenced.
82      *  The option scanning code will skip the "program name" at the start
83      *  of this list of tokens, so we accommodate this way ....
84      */
85     {
86         uintptr_t v = (uintptr_t)(pTL->tkn_list);
87         pOpts->origArgVect = VOIDP(v - sizeof(char *));
88     }
89     pOpts->origArgCt   = (unsigned int)pTL->tkn_ct   + 1;
90     pOpts->fOptSet    &= ~OPTPROC_ERRSTOP;
91 
92     pOpts->curOptIdx   = 1;
93     pOpts->pzCurOpt    = NULL;
94 
95     switch (type) {
96     case ENV_IMM:
97         (void)immediate_opts(pOpts);
98         break;
99 
100     case ENV_ALL:
101         (void)immediate_opts(pOpts);
102         pOpts->curOptIdx = 1;
103         pOpts->pzCurOpt  = NULL;
104         /* FALLTHROUGH */
105 
106     case ENV_NON_IMM:
107         (void)regular_opts(pOpts);
108     }
109 
110     /*
111      *  Free up the temporary arg vector and restore the original program args.
112      */
113     free(pTL);
114     pOpts->origArgVect = sv_argv;
115     pOpts->origArgCt   = (unsigned int)sv_argc;
116     pOpts->fOptSet     = sv_flag;
117 }
118 
119 static void
120 do_env_opt(tOptState * os, char * env_name,
121             tOptions * pOpts, teEnvPresetType type)
122 {
123     os->pzOptArg = getenv(env_name);
124     if (os->pzOptArg == NULL)
125         return;
126 
127     os->flags   = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState;
128     os->optType = TOPT_UNDEFINED;
129 
130     if (  (os->pOD->pz_DisablePfx != NULL)
131        && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) {
132         os->flags |= OPTST_DISABLED;
133         os->pzOptArg = NULL;
134         handle_opt(pOpts, os);
135         return;
136     }
137 
138     switch (type) {
139     case ENV_IMM:
140         /*
141          *  Process only immediate actions
142          */
143         if (DO_IMMEDIATELY(os->flags))
144             break;
145         return;
146 
147     case ENV_NON_IMM:
148         /*
149          *  Process only NON immediate actions
150          */
151         if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags))
152             break;
153         return;
154 
155     default: /* process everything */
156         break;
157     }
158 
159     /*
160      *  Make sure the option value string is persistent and consistent.
161      *
162      *  The interpretation of the option value depends
163      *  on the type of value argument the option takes
164      */
165     if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) {
166         /*
167          *  Ignore any value.
168          */
169         os->pzOptArg = NULL;
170 
171     } else if (os->pzOptArg[0] == NUL) {
172         /*
173          * If the argument is the empty string and the argument is
174          * optional, then treat it as if the option was not specified.
175          */
176         if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0)
177             return;
178         os->pzOptArg = NULL;
179 
180     } else {
181         AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument");
182         os->flags |= OPTST_ALLOC_ARG;
183     }
184 
185     handle_opt(pOpts, os);
186 }
187 
188 /*
189  *  env_presets - check for preset values from the envrionment
190  *  This routine should process in all, immediate or normal modes....
191  */
192 LOCAL void
193 env_presets(tOptions * pOpts, teEnvPresetType type)
194 {
195     int        ct;
196     tOptState  st;
197     char *     pzFlagName;
198     size_t     spaceLeft;
199     char       zEnvName[ AO_NAME_SIZE ];
200 
201     /*
202      *  Finally, see if we are to look at the environment
203      *  variables for initial values.
204      */
205     if ((pOpts->fOptSet & OPTPROC_ENVIRON) == 0)
206         return;
207 
208     doPrognameEnv(pOpts, type);
209 
210     ct  = pOpts->presetOptCt;
211     st.pOD = pOpts->pOptDesc;
212 
213     pzFlagName = zEnvName
214         + snprintf(zEnvName, sizeof(zEnvName), "%s_", pOpts->pzPROGNAME);
215     spaceLeft = AO_NAME_SIZE - (unsigned long)(pzFlagName - zEnvName) - 1;
216 
217     for (;ct-- > 0; st.pOD++) {
218         size_t nln;
219 
220         /*
221          *  If presetting is disallowed, then skip this entry
222          */
223         if (  ((st.pOD->fOptState & OPTST_NO_INIT) != 0)
224            || (st.pOD->optEquivIndex != NO_EQUIVALENT)  )
225             continue;
226 
227         /*
228          *  IF there is no such environment variable,
229          *  THEN skip this entry, too.
230          */
231         nln = strlen(st.pOD->pz_NAME) + 1;
232         if (nln <= spaceLeft) {
233             /*
234              *  Set up the option state
235              */
236             memcpy(pzFlagName, st.pOD->pz_NAME, nln);
237             do_env_opt(&st, zEnvName, pOpts, type);
238         }
239     }
240 
241     /*
242      *  Special handling for ${PROGNAME_LOAD_OPTS}
243      */
244     if (  (pOpts->specOptIdx.save_opts != NO_EQUIVALENT)
245        && (pOpts->specOptIdx.save_opts != 0)) {
246         size_t nln;
247         st.pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
248 
249         if (st.pOD->pz_NAME == NULL)
250             return;
251 
252         nln = strlen(st.pOD->pz_NAME) + 1;
253 
254         if (nln > spaceLeft)
255             return;
256 
257         memcpy(pzFlagName, st.pOD->pz_NAME, nln);
258         do_env_opt(&st, zEnvName, pOpts, type);
259     }
260 }
261 
262 /** @}
263  *
264  * Local Variables:
265  * mode: C
266  * c-file-style: "stroustrup"
267  * indent-tabs-mode: nil
268  * End:
269  * end of autoopts/environment.c */
270