Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple environment variable parser #105

Merged
merged 4 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion include/libspm.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
int get_repos(char** list);
char** get_all_files(const char* root, const char *path, int *num_files);
int download(char* url, FILE* fp);
int parse_env(char** in);


//end test
Expand Down Expand Up @@ -217,7 +218,7 @@


// update the system
int update();

Check warning on line 221 in include/libspm.h

View workflow job for this annotation

GitHub Actions / c-linter

include/libspm.h:221:5 [readability-redundant-declaration]

redundant 'update' declaration

// Function to clean working directories
/*
Expand Down Expand Up @@ -249,7 +250,7 @@
*/
void quit(int status);

int readConfig(const char* configFilePath);
int readConfig(const char* configFilePath, int overwrite);

// Function to check the existence of package locations
/*
Expand Down
4 changes: 2 additions & 2 deletions src/clean.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
// Get the paths to the build and make directories from environment variables
char* build_dir = getenv("SOVIET_BUILD_DIR");
char* make_dir = getenv("SOVIET_MAKE_DIR");
char* cleanups = getenv("SOVIET_CLEANUP");
char* cleanups = strdup(getenv("SOVIET_CLEANUP"));

int result = 0;

char** cleanup_loc;

Check warning on line 24 in src/clean.c

View workflow job for this annotation

GitHub Actions / c-linter

src/clean.c:24:12 [cppcoreguidelines-init-variables]

variable 'cleanup_loc' is not initialized
msg(WARNING, "%s", cleanups);
msg(WARNING, "This will delete: %s", cleanups);
int count = splita(cleanups, ':', &cleanup_loc);

for(int i = 0; i < count; i++)
Expand Down
12 changes: 7 additions & 5 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
const char* default_value;
} ConfigEntry;

ConfigEntry configEntries[] = {

Check warning on line 19 in src/config.c

View workflow job for this annotation

GitHub Actions / c-linter

src/config.c:19:13 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'configEntries' is non-const and globally accessible, consider making it const
{ "SOVIET_ROOT", "/" },
{ "SOVIET_DEFAULT_FORMAT", "ecmp" },
{ "SOVIET_MAIN_DIR", "/var/cccp" },
Expand All @@ -41,7 +41,7 @@
// The number of entries in the configEntries array
const size_t numConfigEntries = sizeof(configEntries) / sizeof(configEntries[0]);

int readConfig(const char* configFilePath)
int readConfig(const char* configFilePath, int overwrite)
{
if (configFilePath == NULL) {
configFilePath = DEFAULT_CONFIG_FILE; // Use the default config file path
Expand Down Expand Up @@ -74,10 +74,11 @@
}
}

char line[1024];
char* line = calloc(1024, 1);

while (fgets(line, sizeof(line), file)) {
while (fgets(line, 1024, file)) {
line[strlen(line) - 1] = 0;
parse_env(&line);

if((line[0] != '#' || (line[0] != '/' && line[1] != '/')) && strstr(line, "=") != 0)
{
Expand All @@ -93,16 +94,17 @@
dbg(2, "Key: %s Value: %s", key, value);

// Set environment variables based on the key-value pairs in the config file
setenv(key, value, 0);
setenv(key, value, overwrite);
}
}

free(line);
fclose(file);

// Set environment variables for missing keys with their default values
for (size_t i = 0; i < numConfigEntries; i++) {
if (getenv(configEntries[i].key) == NULL) {
setenv(configEntries[i].key, configEntries[i].default_value, 0);
setenv(configEntries[i].key, configEntries[i].default_value, overwrite);
}
}

Expand Down
85 changes: 85 additions & 0 deletions src/environment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "stdio.h"
#include <stdlib.h>
#include <string.h>

#include "libspm.h"
#include "globals.h"
#include "cutils.h"

#include <stdbool.h>

// This will parse a string for environment variables
// It makes an assumption that a variable is: $A-Z_0-9

int parse_env(char** in)
{
dbg(2, "Parsing string %s for env variables", *in);
char* env = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_";
char* start = strchr(*in, '$');
char* end = NULL;
int i, start_i;

Check warning on line 20 in src/environment.c

View workflow job for this annotation

GitHub Actions / c-linter

src/environment.c:20:5 [readability-isolate-declaration]

multiple declarations in a single statement reduces readability

Check warning on line 20 in src/environment.c

View workflow job for this annotation

GitHub Actions / c-linter

src/environment.c:20:9 [cppcoreguidelines-init-variables]

variable 'i' is not initialized

Check warning on line 20 in src/environment.c

View workflow job for this annotation

GitHub Actions / c-linter

src/environment.c:20:12 [cppcoreguidelines-init-variables]

variable 'start_i' is not initialized

if (start == NULL)
{
return 0;
}

dbg(2, "Start: %s", start);

start_i = strlen(*in) - strlen(start);

dbg(2, "Start i: %d, from '%d' and '%d'", start_i, strlen(*in), strlen(start));

for (i = 1; i < strlen(start); i++)
{
end = strchr(env, start[i]);

if (end == NULL)
{
if(i == 0)
{
return 0;
}

if(start[i] != '\0')
{
end = &start[i];
}

break;
}

if(i + 1 == strlen(start))
{
end = " ";
}
}

char* var = strdup(*in + start_i + 1);
var[--i] = '\0';
(*in)[start_i] = '\0';

dbg(2, "Var: %s", var);
dbg(2, "In: %s", *in);

char* full_var = getenv(var);

if(full_var == NULL)
{
return 0;
}

dbg(2, "Full var: %s", full_var);

char* full_in = calloc(strlen(*in) + strlen(full_var) + strlen(end) + 1, 1);

Check warning on line 74 in src/environment.c

View workflow job for this annotation

GitHub Actions / c-linter

src/environment.c:74:61 [clang-analyzer-core.NonNullParamChecker]

Null pointer passed to 1st parameter expecting 'nonnull'

sprintf(full_in, "%s%s%s", *in, full_var, end);

Check warning on line 76 in src/environment.c

View workflow job for this annotation

GitHub Actions / c-linter

src/environment.c:76:5 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]

Call to function 'sprintf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11

free(*in);
free(var);
*in = full_in;

dbg(2, "Result: %s", *in);

return parse_env(in);
}
2 changes: 1 addition & 1 deletion src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
setenv("SOVIET_CONFIG_FILE", "/etc/cccp.conf", 0);
setenv("SOVIET_REPOS_LIST", "/etc/sources.list", 0);
dbg(3, "Cleaning...");
readConfig(getenv("SOVIET_CONFIG_FILE"));
readConfig(getenv("SOVIET_CONFIG_FILE"), 0);

dbg(3, "Setting variables");

Expand All @@ -35,12 +35,12 @@
msg(ERROR, "SOVIET_FORMATS environment variable not set");
exit(1);
}
char** formats;

Check warning on line 38 in src/init.c

View workflow job for this annotation

GitHub Actions / c-linter

src/init.c:38:12 [cppcoreguidelines-init-variables]

variable 'formats' is not initialized
int format_count = splita(strdup(formats_env), ' ', &formats);
for (int i = 0; i < format_count; i++) {
char* format = formats[i];
char plugin[MAX_PATH];
sprintf(plugin, "%s/%s.so", getenv("SOVIET_PLUGIN_DIR"), format);

Check warning on line 43 in src/init.c

View workflow job for this annotation

GitHub Actions / c-linter

src/init.c:43:9 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]

Call to function 'sprintf' is insecure as it does not provide bounding of the memory buffer or security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'sprintf_s' in case of C11
dbg(2, "Checking for %s plugin install", plugin);

// Check if the format plugin exists
Expand Down
21 changes: 2 additions & 19 deletions src/install.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ int install_package_source(const char* spm_path, int as_dep) {
- -1: Installation failed.
*/
int f_install_package_source(const char* spm_path, int as_dep, char* repo) {

// Read the config in case anything got overwritten in the ecmp file

readConfig(getenv("SOVIET_CONFIG_FILE"));

// Check if spm_path is NULL

if (spm_path == NULL) {
Expand Down Expand Up @@ -89,7 +84,7 @@ int f_install_package_source(const char* spm_path, int as_dep, char* repo) {
char* env_path = calloc(MAX_PATH, 1);
sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg.environment);

readConfig(env_path);
readConfig(env_path, 1);
}

// Set global environment variables
Expand Down Expand Up @@ -140,15 +135,7 @@ int f_install_package_source(const char* spm_path, int as_dep, char* repo) {

if (pkg.url != NULL)
{
/* IMPORTANT*/
// This seemingly pointless piece of code is actually very important
// Basically it evaluate the nested variables in the URL
// without it everything crashes
// I dont like calling exec() so its a temporary solution
// I dont know how to fix it without manually parsing eveything, a pain
char cmd[1024];
sprintf(cmd,"echo %s",pkg.url);
pkg.url = exec(cmd);
parse_env(&(pkg.url));
dbg(1, "URL: %s", pkg.url);
setenv("URL", pkg.url, 1);
}
Expand Down Expand Up @@ -309,10 +296,6 @@ __attribute__((unused)) int uncompress_binary(const char* bin_path, const char*
*/
int install_package_binary(const char* archivePath, int as_dep, const char* repo) {

// Read the config in case anything got overwritten in the ecmp file

readConfig(getenv("SOVIET_CONFIG_FILE"));

struct package pkg;

// Get required environment variables
Expand Down
2 changes: 2 additions & 0 deletions src/make.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ int make(char* package_dir, struct package* pkg) {

// This seems stupid, but should work
char* file_name = strtok(pkg->files[i], " ");
parse_env(&file_name);
char* file_url = strtok(NULL, " ");
parse_env(&file_url);
char* file_sha256 = strtok(NULL, " ");

sprintf(location, "%s/%s", getenv("SOVIET_MAKE_DIR"), file_name);
Expand Down
8 changes: 3 additions & 5 deletions test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void test_move() {
dbg(2,"creating test files");
// make all files
for (int i = 0; i < l_f_count; i++)
{
{
dbg(3,"Creating %s\n",l_files[i]);
char* path = malloc(256);
sprintf(path,"%s/%s",build_dir,l_files[i]);
Expand Down Expand Up @@ -147,9 +147,7 @@ void test_make(char* spm_path) {
setenv("NAME", p.name, 1);
setenv("VERSION", p.version, 1);
if (p.url != NULL) {
char cmd[1024];
sprintf(cmd,"echo %s",p.url);
p.url = exec(cmd);
parse_env(&(p.url));
dbg(1, "URL: %s", p.url);
setenv("URL", p.url, 1);
}
Expand Down Expand Up @@ -202,7 +200,7 @@ void test_config() {

msg(INFO,"Testing 'readConfig()'..");

assert(readConfig(getenv("SOVIET_CONFIG_FILE")) == 0);
assert(readConfig(getenv("SOVIET_CONFIG_FILE"), 0) == 0);
return;
}

Expand Down
Loading