1 /*
2     Copyright (c) 2014-2016 Intel Corporation.  All Rights Reserved.
3 
4     Redistribution and use in source and binary forms, with or without
5     modification, are permitted provided that the following conditions
6     are met:
7 
8       * Redistributions of source code must retain the above copyright
9         notice, this list of conditions and the following disclaimer.
10       * Redistributions in binary form must reproduce the above copyright
11         notice, this list of conditions and the following disclaimer in the
12         documentation and/or other materials provided with the distribution.
13       * Neither the name of Intel Corporation nor the names of its
14         contributors may be used to endorse or promote products derived
15         from this software without specific prior written permission.
16 
17     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 
31 #include "offload_env.h"
32 #include <string.h>
33 #include <ctype.h>
34 #include "offload_util.h"
35 #include "liboffload_error_codes.h"
36 
37 // for environment variables valid on all cards
38 const int MicEnvVar::any_card = -1;
39 
~MicEnvVar()40 MicEnvVar::~MicEnvVar()
41 {
42     for (std::list<MicEnvVar::CardEnvVars*>::const_iterator
43          it = card_spec_list.begin();
44          it != card_spec_list.end(); it++) {
45         CardEnvVars *card_data = *it;
46         delete card_data;
47     }
48 }
49 
~VarValue()50 MicEnvVar::VarValue::~VarValue()
51 {
52     free(env_var_value);
53 }
54 
~CardEnvVars()55 MicEnvVar::CardEnvVars::~CardEnvVars()
56 {
57     for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin();
58         it != env_vars.end(); it++) {
59             VarValue *var_value = *it;
60             delete var_value;
61     }
62 }
63 
64 // Searching for card in "card_spec_list" list with the same "number"
65 
get_card(int number)66 MicEnvVar::CardEnvVars* MicEnvVar::get_card(int number)
67 {
68     if (number == any_card) {
69         return &common_vars;
70     }
71     for (std::list<MicEnvVar::CardEnvVars*>::const_iterator
72          it = card_spec_list.begin();
73          it != card_spec_list.end(); it++) {
74         CardEnvVars *card_data = *it;
75         if (card_data->card_number == number) {
76             return card_data;
77         }
78     }
79     return NULL;
80 }
81 
82 // Searching for environment variable in "env_var" list with the same name
83 
find_var(char * env_var_name,int env_var_name_length)84 MicEnvVar::VarValue* MicEnvVar::CardEnvVars::find_var(
85     char* env_var_name,
86     int env_var_name_length
87 )
88 {
89     for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin();
90         it != env_vars.end(); it++) {
91             VarValue *var_value = *it;
92             if (var_value->length == env_var_name_length &&
93                 !strncmp(var_value->env_var, env_var_name,
94                          env_var_name_length)) {
95                 return var_value;
96             }
97     }
98     return NULL;
99 }
100 
analyze_env_var(char * env_var_string)101 void MicEnvVar::analyze_env_var(char *env_var_string)
102 {
103     char          *env_var_name;
104     char          *env_var_def;
105     int           card_number;
106     int           env_var_name_length;
107     MicEnvVarKind env_var_kind;
108 
109     env_var_kind = get_env_var_kind(env_var_string,
110                                     &card_number,
111                                     &env_var_name,
112                                     &env_var_name_length,
113                                     &env_var_def);
114     switch (env_var_kind) {
115         case c_mic_var:
116         case c_mic_card_var:
117             add_env_var(card_number,
118                         env_var_name,
119                         env_var_name_length,
120                         env_var_def);
121             break;
122         case c_mic_card_env:
123             mic_parse_env_var_list(card_number, env_var_def);
124             break;
125         case c_no_mic:
126         default:
127             break;
128     }
129 }
130 
add_env_var(int card_number,char * env_var_name,int env_var_name_length,char * env_var_def)131 void MicEnvVar::add_env_var(
132     int card_number,
133     char *env_var_name,
134     int env_var_name_length,
135     char *env_var_def
136 )
137 {
138     VarValue *var;
139     CardEnvVars *card;
140 
141     // The case corresponds to common env var definition of kind
142     // <mic-prefix>_<var>
143     if (card_number == any_card) {
144         card = &common_vars;
145     }
146     else {
147         card = get_card(card_number);
148         if (!card) {
149             // definition for new card occurred
150             card = new CardEnvVars(card_number);
151             card_spec_list.push_back(card);
152         }
153 
154     }
155     var = card->find_var(env_var_name, env_var_name_length);
156     if (!var) {
157         // put new env var definition in "env_var" list
158         var = new VarValue(env_var_name, env_var_name_length, env_var_def);
159         card->env_vars.push_back(var);
160     }
161 }
162 
163 // The routine analyses string pointed by "env_var_string" argument
164 // according to the following syntax:
165 //
166 // Specification of prefix for MIC environment variables
167 // MIC_ENV_PREFIX=<mic-prefix>
168 //
169 // Setting single MIC environment variable
170 // <mic-prefix>_<var>=<value>
171 // <mic-prefix>_<card-number>_<var>=<value>
172 
173 // Setting multiple MIC environment variables
174 // <mic-prefix>_<card-number>_ENV=<env-vars>
175 
get_env_var_kind(char * env_var_string,int * card_number,char ** env_var_name,int * env_var_name_length,char ** env_var_def)176 MicEnvVarKind MicEnvVar::get_env_var_kind(
177     char *env_var_string,
178     int *card_number,
179     char **env_var_name,
180     int *env_var_name_length,
181     char **env_var_def
182 )
183 {
184     int len = strlen(prefix);
185     char *c = env_var_string;
186     int num = 0;
187     bool card_is_set = false;
188 
189     if (strncmp(c, prefix, len) != 0 || c[len] != '_') {
190             return c_no_mic;
191     }
192     c += len + 1;
193 
194     *card_number = any_card;
195     if (isdigit(*c)) {
196         while (isdigit (*c)) {
197             num = (*c++ - '0') + (num * 10);
198         }
199     if (*c != '_') {
200         return c_no_mic;
201     }
202     c++;
203         *card_number = num;
204         card_is_set = true;
205     }
206     if (!isalpha(*c)) {
207         return c_no_mic;
208     }
209     *env_var_name = *env_var_def = c;
210     if (strncmp(c, "ENV=", 4) == 0) {
211         if (!card_is_set) {
212             *env_var_name_length = 3;
213             *env_var_name = *env_var_def = c;
214             *env_var_def = strdup(*env_var_def);
215             if (*env_var_def == NULL)
216                 LIBOFFLOAD_ERROR(c_malloc);
217             return  c_mic_var;
218         }
219         *env_var_def = c + strlen("ENV=");
220         *env_var_def = strdup(*env_var_def);
221         if (*env_var_def == NULL)
222             LIBOFFLOAD_ERROR(c_malloc);
223         return c_mic_card_env;
224     }
225     if (isalpha(*c)) {
226         *env_var_name_length = 0;
227         while (isalnum(*c) || *c == '_') {
228             c++;
229             (*env_var_name_length)++;
230         }
231     }
232     if (*c != '=') {
233         return c_no_mic;
234     }
235     *env_var_def = strdup(*env_var_def);
236     if (*env_var_def == NULL)
237         LIBOFFLOAD_ERROR(c_malloc);
238     return card_is_set? c_mic_card_var : c_mic_var;
239 }
240 
241 // analysing <env-vars> in form:
242 // <mic-prefix>_<card-number>_ENV=<env-vars>
243 // where:
244 //
245 // <env-vars>:
246 //                <env-var>
247 //                <env-vars> | <env-var>
248 //
249 // <env-var>:
250 //                variable=value
251 //                variable="value"
252 //                variable=
253 
mic_parse_env_var_list(int card_number,char * env_vars_def_list)254 void MicEnvVar::mic_parse_env_var_list(
255     int card_number, char *env_vars_def_list)
256 {
257     char *c = env_vars_def_list;
258     char *env_var_name;
259     int  env_var_name_length;
260     char *env_var_def;
261     bool var_is_quoted;
262 
263     if (*c == '"') {
264         c++;
265     }
266     while (*c != 0) {
267         var_is_quoted = false;
268         env_var_name = c;
269         env_var_name_length = 0;
270         if (isalpha(*c)) {
271             while (isalnum(*c) || *c == '_') {
272                 c++;
273                 env_var_name_length++;
274             }
275         }
276         else {
277             LIBOFFLOAD_ERROR(c_mic_parse_env_var_list1);
278             return;
279         }
280         if (*c != '=') {
281             LIBOFFLOAD_ERROR(c_mic_parse_env_var_list2);
282             return;
283         }
284         c++;
285 
286         if (*c == '"') {
287             var_is_quoted = true;
288             c++;
289         }
290         // Environment variable values that contain | will need to be escaped.
291         while (*c != 0 && *c != '|' &&
292                (!var_is_quoted || *c != '"'))
293         {
294             // skip escaped symbol
295             if (*c == '\\') {
296                 c++;
297             }
298             c++;
299         }
300         if (var_is_quoted) {
301             c++; // for "
302             while (*c != 0 && *c != '|') {
303                 c++;
304             }
305         }
306 
307         int sz = c - env_var_name;
308         env_var_def = (char*)malloc(sz);
309         if (env_var_def == NULL)
310           LIBOFFLOAD_ERROR(c_malloc);
311         memcpy(env_var_def, env_var_name, sz);
312         env_var_def[sz] = 0;
313 
314         if (*c == '|') {
315             c++;
316             while (*c != 0 && *c == ' ') {
317                 c++;
318             }
319         }
320         add_env_var(card_number,
321                     env_var_name,
322                     env_var_name_length,
323                     env_var_def);
324     }
325 }
326 
327 // Collect all definitions for the card with number "card_num".
328 // The returned result is vector of string pointers defining one
329 // environment variable. The vector is terminated by NULL pointer.
330 // In the beginning of the vector there are env vars defined as
331 // <mic-prefix>_<card-number>_<var>=<value>
332 // or
333 // <mic-prefix>_<card-number>_ENV=<env-vars>
334 // where <card-number> is equal to "card_num"
335 // They are followed by definitions valid for any card
336 // and absent in previous definitions.
337 
create_environ_for_card(int card_num)338 char** MicEnvVar::create_environ_for_card(int card_num)
339 {
340     VarValue *var_value;
341     VarValue *var_value_find;
342     CardEnvVars *card_data = get_card(card_num);
343     CardEnvVars *card_data_common;
344     std::list<char*> new_env;
345     char **rez;
346 
347     if (!prefix) {
348         return NULL;
349     }
350     // There is no personel env var definitions for the card with
351     // number "card_num"
352     if (!card_data) {
353         return create_environ_for_card(any_card);
354     }
355 
356     for (std::list<MicEnvVar::VarValue*>::const_iterator
357          it = card_data->env_vars.begin();
358          it != card_data->env_vars.end(); it++) {
359         var_value = *it;
360         new_env.push_back(var_value->env_var_value);
361     }
362 
363     if (card_num != any_card) {
364         card_data_common = get_card(any_card);
365         for (std::list<MicEnvVar::VarValue*>::const_iterator
366              it = card_data_common->env_vars.begin();
367              it != card_data_common->env_vars.end(); it++) {
368             var_value = *it;
369             var_value_find = card_data->find_var(var_value->env_var,
370                                                  var_value->length);
371             if (!var_value_find) {
372                 new_env.push_back(var_value->env_var_value);
373             }
374         }
375     }
376 
377     int new_env_size = new_env.size();
378     rez = (char**) malloc((new_env_size + 1) * sizeof(char*));
379     if (rez == NULL)
380       LIBOFFLOAD_ERROR(c_malloc);
381     std::copy(new_env.begin(), new_env.end(), rez);
382     rez[new_env_size] = 0;
383     return rez;
384 }
385