| /* | |
| Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved. | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions | |
| are met: | |
| * Redistributions of source code must retain the above copyright | |
| notice, this list of conditions and the following disclaimer. | |
| * Redistributions in binary form must reproduce the above copyright | |
| notice, this list of conditions and the following disclaimer in the | |
| documentation and/or other materials provided with the distribution. | |
| * Neither the name of Intel Corporation nor the names of its | |
| contributors may be used to endorse or promote products derived | |
| from this software without specific prior written permission. | |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "offload_env.h" | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include "offload_util.h" | |
| #include "liboffload_error_codes.h" | |
| // for environment variables valid on all cards | |
| const int MicEnvVar::any_card = -1; | |
| MicEnvVar::~MicEnvVar() | |
| { | |
| for (std::list<MicEnvVar::CardEnvVars*>::const_iterator | |
| it = card_spec_list.begin(); | |
| it != card_spec_list.end(); it++) { | |
| CardEnvVars *card_data = *it; | |
| delete card_data; | |
| } | |
| } | |
| MicEnvVar::VarValue::~VarValue() | |
| { | |
| free(env_var_value); | |
| } | |
| MicEnvVar::CardEnvVars::~CardEnvVars() | |
| { | |
| for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin(); | |
| it != env_vars.end(); it++) { | |
| VarValue *var_value = *it; | |
| delete var_value; | |
| } | |
| } | |
| // Searching for card in "card_spec_list" list with the same "number" | |
| MicEnvVar::CardEnvVars* MicEnvVar::get_card(int number) | |
| { | |
| if (number == any_card) { | |
| return &common_vars; | |
| } | |
| for (std::list<MicEnvVar::CardEnvVars*>::const_iterator | |
| it = card_spec_list.begin(); | |
| it != card_spec_list.end(); it++) { | |
| CardEnvVars *card_data = *it; | |
| if (card_data->card_number == number) { | |
| return card_data; | |
| } | |
| } | |
| return NULL; | |
| } | |
| // Searching for environment variable in "env_var" list with the same name | |
| MicEnvVar::VarValue* MicEnvVar::CardEnvVars::find_var( | |
| char* env_var_name, | |
| int env_var_name_length | |
| ) | |
| { | |
| for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin(); | |
| it != env_vars.end(); it++) { | |
| VarValue *var_value = *it; | |
| if (var_value->length == env_var_name_length && | |
| !strncmp(var_value->env_var, env_var_name, | |
| env_var_name_length)) { | |
| return var_value; | |
| } | |
| } | |
| return NULL; | |
| } | |
| void MicEnvVar::analyze_env_var(char *env_var_string) | |
| { | |
| char *env_var_name; | |
| char *env_var_def; | |
| int card_number; | |
| int env_var_name_length; | |
| MicEnvVarKind env_var_kind; | |
| env_var_kind = get_env_var_kind(env_var_string, | |
| &card_number, | |
| &env_var_name, | |
| &env_var_name_length, | |
| &env_var_def); | |
| switch (env_var_kind) { | |
| case c_mic_var: | |
| case c_mic_card_var: | |
| add_env_var(card_number, | |
| env_var_name, | |
| env_var_name_length, | |
| env_var_def); | |
| break; | |
| case c_mic_card_env: | |
| mic_parse_env_var_list(card_number, env_var_def); | |
| break; | |
| case c_no_mic: | |
| default: | |
| break; | |
| } | |
| } | |
| void MicEnvVar::add_env_var( | |
| int card_number, | |
| char *env_var_name, | |
| int env_var_name_length, | |
| char *env_var_def | |
| ) | |
| { | |
| VarValue *var; | |
| CardEnvVars *card; | |
| // The case corresponds to common env var definition of kind | |
| // <mic-prefix>_<var> | |
| if (card_number == any_card) { | |
| card = &common_vars; | |
| } | |
| else { | |
| card = get_card(card_number); | |
| if (!card) { | |
| // definition for new card occurred | |
| card = new CardEnvVars(card_number); | |
| card_spec_list.push_back(card); | |
| } | |
| } | |
| var = card->find_var(env_var_name, env_var_name_length); | |
| if (!var) { | |
| // put new env var definition in "env_var" list | |
| var = new VarValue(env_var_name, env_var_name_length, env_var_def); | |
| card->env_vars.push_back(var); | |
| } | |
| } | |
| // The routine analyses string pointed by "env_var_string" argument | |
| // according to the following syntax: | |
| // | |
| // Specification of prefix for MIC environment variables | |
| // MIC_ENV_PREFIX=<mic-prefix> | |
| // | |
| // Setting single MIC environment variable | |
| // <mic-prefix>_<var>=<value> | |
| // <mic-prefix>_<card-number>_<var>=<value> | |
| // Setting multiple MIC environment variables | |
| // <mic-prefix>_<card-number>_ENV=<env-vars> | |
| MicEnvVarKind MicEnvVar::get_env_var_kind( | |
| char *env_var_string, | |
| int *card_number, | |
| char **env_var_name, | |
| int *env_var_name_length, | |
| char **env_var_def | |
| ) | |
| { | |
| int len = strlen(prefix); | |
| char *c = env_var_string; | |
| int num = 0; | |
| bool card_is_set = false; | |
| if (strncmp(c, prefix, len) != 0 || c[len] != '_') { | |
| return c_no_mic; | |
| } | |
| c += len + 1; | |
| *card_number = any_card; | |
| if (isdigit(*c)) { | |
| while (isdigit (*c)) { | |
| num = (*c++ - '0') + (num * 10); | |
| } | |
| if (*c != '_') { | |
| return c_no_mic; | |
| } | |
| c++; | |
| *card_number = num; | |
| card_is_set = true; | |
| } | |
| if (!isalpha(*c)) { | |
| return c_no_mic; | |
| } | |
| *env_var_name = *env_var_def = c; | |
| if (strncmp(c, "ENV=", 4) == 0) { | |
| if (!card_is_set) { | |
| *env_var_name_length = 3; | |
| *env_var_name = *env_var_def = c; | |
| *env_var_def = strdup(*env_var_def); | |
| if (*env_var_def == NULL) | |
| LIBOFFLOAD_ERROR(c_malloc); | |
| return c_mic_var; | |
| } | |
| *env_var_def = c + strlen("ENV="); | |
| *env_var_def = strdup(*env_var_def); | |
| if (*env_var_def == NULL) | |
| LIBOFFLOAD_ERROR(c_malloc); | |
| return c_mic_card_env; | |
| } | |
| if (isalpha(*c)) { | |
| *env_var_name_length = 0; | |
| while (isalnum(*c) || *c == '_') { | |
| c++; | |
| (*env_var_name_length)++; | |
| } | |
| } | |
| if (*c != '=') { | |
| return c_no_mic; | |
| } | |
| *env_var_def = strdup(*env_var_def); | |
| if (*env_var_def == NULL) | |
| LIBOFFLOAD_ERROR(c_malloc); | |
| return card_is_set? c_mic_card_var : c_mic_var; | |
| } | |
| // analysing <env-vars> in form: | |
| // <mic-prefix>_<card-number>_ENV=<env-vars> | |
| // where: | |
| // | |
| // <env-vars>: | |
| // <env-var> | |
| // <env-vars> | <env-var> | |
| // | |
| // <env-var>: | |
| // variable=value | |
| // variable="value" | |
| // variable= | |
| void MicEnvVar::mic_parse_env_var_list( | |
| int card_number, char *env_vars_def_list) | |
| { | |
| char *c = env_vars_def_list; | |
| char *env_var_name; | |
| int env_var_name_length; | |
| char *env_var_def; | |
| bool var_is_quoted; | |
| if (*c == '"') { | |
| c++; | |
| } | |
| while (*c != 0) { | |
| var_is_quoted = false; | |
| env_var_name = c; | |
| env_var_name_length = 0; | |
| if (isalpha(*c)) { | |
| while (isalnum(*c) || *c == '_') { | |
| c++; | |
| env_var_name_length++; | |
| } | |
| } | |
| else { | |
| LIBOFFLOAD_ERROR(c_mic_parse_env_var_list1); | |
| return; | |
| } | |
| if (*c != '=') { | |
| LIBOFFLOAD_ERROR(c_mic_parse_env_var_list2); | |
| return; | |
| } | |
| c++; | |
| if (*c == '"') { | |
| var_is_quoted = true; | |
| c++; | |
| } | |
| // Environment variable values that contain | will need to be escaped. | |
| while (*c != 0 && *c != '|' && | |
| (!var_is_quoted || *c != '"')) | |
| { | |
| // skip escaped symbol | |
| if (*c == '\\') { | |
| c++; | |
| } | |
| c++; | |
| } | |
| if (var_is_quoted) { | |
| c++; // for " | |
| while (*c != 0 && *c != '|') { | |
| c++; | |
| } | |
| } | |
| int sz = c - env_var_name; | |
| env_var_def = (char*)malloc(sz); | |
| if (env_var_def == NULL) | |
| LIBOFFLOAD_ERROR(c_malloc); | |
| memcpy(env_var_def, env_var_name, sz); | |
| env_var_def[sz] = 0; | |
| if (*c == '|') { | |
| c++; | |
| while (*c != 0 && *c == ' ') { | |
| c++; | |
| } | |
| } | |
| add_env_var(card_number, | |
| env_var_name, | |
| env_var_name_length, | |
| env_var_def); | |
| } | |
| } | |
| // Collect all definitions for the card with number "card_num". | |
| // The returned result is vector of string pointers defining one | |
| // environment variable. The vector is terminated by NULL pointer. | |
| // In the beginning of the vector there are env vars defined as | |
| // <mic-prefix>_<card-number>_<var>=<value> | |
| // or | |
| // <mic-prefix>_<card-number>_ENV=<env-vars> | |
| // where <card-number> is equal to "card_num" | |
| // They are followed by definitions valid for any card | |
| // and absent in previous definitions. | |
| char** MicEnvVar::create_environ_for_card(int card_num) | |
| { | |
| VarValue *var_value; | |
| VarValue *var_value_find; | |
| CardEnvVars *card_data = get_card(card_num); | |
| CardEnvVars *card_data_common; | |
| std::list<char*> new_env; | |
| char **rez; | |
| if (!prefix) { | |
| return NULL; | |
| } | |
| // There is no personel env var definitions for the card with | |
| // number "card_num" | |
| if (!card_data) { | |
| return create_environ_for_card(any_card); | |
| } | |
| for (std::list<MicEnvVar::VarValue*>::const_iterator | |
| it = card_data->env_vars.begin(); | |
| it != card_data->env_vars.end(); it++) { | |
| var_value = *it; | |
| new_env.push_back(var_value->env_var_value); | |
| } | |
| if (card_num != any_card) { | |
| card_data_common = get_card(any_card); | |
| for (std::list<MicEnvVar::VarValue*>::const_iterator | |
| it = card_data_common->env_vars.begin(); | |
| it != card_data_common->env_vars.end(); it++) { | |
| var_value = *it; | |
| var_value_find = card_data->find_var(var_value->env_var, | |
| var_value->length); | |
| if (!var_value_find) { | |
| new_env.push_back(var_value->env_var_value); | |
| } | |
| } | |
| } | |
| int new_env_size = new_env.size(); | |
| rez = (char**) malloc((new_env_size + 1) * sizeof(char*)); | |
| if (rez == NULL) | |
| LIBOFFLOAD_ERROR(c_malloc); | |
| std::copy(new_env.begin(), new_env.end(), rez); | |
| rez[new_env_size] = 0; | |
| return rez; | |
| } |