diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 2d3aa6a..53530ce 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -22,6 +22,10 @@ jobs: run: | sudo apt-get update sudo apt-get install -y libcurl4-openssl-dev + - name: Install libsqlite3-dev + run: | + sudo apt-get update + sudo apt-get install -y libsqlite3-dev - name: Install libgit2 run: | curl -L https://codeload.github.com/libgit2/libgit2/tar.gz/refs/tags/v1.8.1 --output libgit2-1.8.1.tar.gz diff --git a/compile_flags.txt b/compile_flags.txt deleted file mode 100644 index 43fa758..0000000 --- a/compile_flags.txt +++ /dev/null @@ -1 +0,0 @@ --I./include diff --git a/formats/ecmp/ecmp.c b/formats/ecmp/ecmp.c index 2eb2f6b..167b607 100644 --- a/formats/ecmp/ecmp.c +++ b/formats/ecmp/ecmp.c @@ -45,49 +45,47 @@ int open(char* path,struct package* pkg) } void* parsers[][3] = { - {parseinfo,pkg,NULL}, + {parseinfo,&pkg,NULL}, - {parseraw,&pkg->info.make,NULL}, {parseraw,&pkg->info.install,NULL}, - {parseraw,&pkg->info.download,NULL}, {parseraw,&pkg->info.prepare,NULL}, {parseraw,&pkg->info.special,NULL}, {parsenl,&pkg->files,&pkg->filesCount}, {parsenl,&pkg->dependencies,&pkg->dependenciesCount}, {parsenl,&pkg->optional,&pkg->optionalCount}, - {parsenl,&pkg->inputs,&pkg->inputsCount}, + {parsenl,&pkg->locations,&pkg->locationsCount}, - {parseraw,&pkg->info.description,NULL}, - {parsenl,&pkg->exports,&pkg->exportsCount} + {parseraw,&pkg->description,NULL}, + {parsenl,&pkg->config,&pkg->configCount} }; void* pairs[][2] = { {"info",parsers[0]}, - {"make",parsers[1]}, - {"install",parsers[2]}, - {"download",parsers[3]}, - {"prepare",parsers[4]}, - {"special",parsers[5]}, - - {"files",parsers[6]}, - {"dependencies",parsers[7]}, - {"optional",parsers[8]}, - {"inputs",parsers[9]}, - {"locations",parsers[10]}, - {"description",parsers[11]}, - {"exports",parsers[12]}, + {"install",parsers[1]}, + {"prepare",parsers[2]}, + {"special",parsers[3]}, + + {"files",parsers[4]}, + {"dependencies",parsers[5]}, + {"optional",parsers[6]}, + + {"locations",parsers[7]}, + {"description",parsers[8]}, + {"config",parsers[9]}, {NULL,NULL} }; void* infodict[][2] = { + // This is very stupid, but basically I assume that the name was obtained from the database + // This is to go around a memory leak caused by overwriting name when opening a package + // This is very stupid {"name",&pkg->name}, {"version",&pkg->version}, {"type",&pkg->type}, {"url",&pkg->url}, {"license",&pkg->license}, - {"sha256",&pkg->sha256}, {"environment",&pkg->environment}, {NULL,NULL} }; @@ -104,7 +102,7 @@ int open(char* path,struct package* pkg) for (unsigned int i = 0; i < count; i++) { void** options = hm_get(hm,sections[i]->name); if (options == NULL) { - msg(WARNING,"Unknown section : %s",sections[i]->name); + msg(FATAL,"Unknown section : %s",sections[i]->name); free(sections[i]->buff); continue; } @@ -118,7 +116,7 @@ int open(char* path,struct package* pkg) } else { - msg(WARNING,"Unknown parser for section : %s",sections[i]->name); + msg(FATAL,"Unknown parser for section : %s",sections[i]->name); } } dbg(2,"done parsing | returning"); @@ -126,6 +124,7 @@ int open(char* path,struct package* pkg) // free sections for (unsigned int i = 0; i < count; i++) { free(sections[i]->name); + free(sections[i]->buff); free(sections[i]); } free(sections); @@ -141,10 +140,10 @@ int open(char* path,struct package* pkg) unsigned int parsenl(char* s,char*** dest) { - char* str; + //char* str; // the parseraw below is useless but i'll keep since in case - parseraw(s,&str); - return splita(str,'\n',dest); + //parseraw(s,&str); + return splita(s,'\n',dest); } unsigned int parseraw(char* s, char** dest) { @@ -153,7 +152,7 @@ unsigned int parseraw(char* s, char** dest) // So we are just going to copy the pointer to it // In the last version , we were copying the string to a new buffer // Because the `s` string was a buffer that was going to be freed by `getline()` - *dest = s; + *dest = strdup(s); return strlen(s); } @@ -180,14 +179,21 @@ unsigned int parseinfo(char *s, struct package* dest) { char* key = strtok(nlist[i], "="); char* value = strtok(NULL, "="); if (key == NULL || value == NULL) { - msg(WARNING, "Invalid key-value pair: '%s'", nlist[i]); + msg(FATAL, "Invalid key-value pair: '%s'", nlist[i]); continue; } // add to corresponding value in dict char** destbuff = hm_get(infohm, key); + + if(strcmp(key, "name") == 0) + { + // This is very stupid + free(nlist[i]); + continue; + } if (destbuff == NULL) { - msg(WARNING, "Unknown key : '%s'", key); + msg(FATAL, "Unknown key : '%s'", key); continue; } @@ -195,14 +201,15 @@ unsigned int parseinfo(char *s, struct package* dest) { if (*destbuff == NULL) { msg(ERROR, "Error allocating memory for %s value", key); free(nlist); - free(s); + //free(s); return 0; } dbg(3, "Setting destbuff to %p - %s", *destbuff, *destbuff); + free(nlist[i]); } free(nlist); - free(s); + //free(s); return 0; } @@ -221,7 +228,8 @@ unsigned int getsections(char* path,section*** sections) { (void)current; unsigned int alloc = 0; - while ((read = getline(&line,&len,fp)) != EOF) { + while ((read = getline(&line,&len,fp)) != EOF) + { if (line[0] == '#' || line[0] == '\n' || strlen(line) < 2) { continue; } @@ -246,6 +254,7 @@ unsigned int getsections(char* path,section*** sections) { } strcat((*sections)[sectionscount-1]->buff,line); } + free(line); return sectionscount; } @@ -259,15 +268,13 @@ int create(const char* path,struct package* pkg) // i love hashmaps but here we'll use maparray // we have the list[0] = section and list[1] = function to do stuff void* list[][3] = { - {"download",pkg->info.download,NULL}, {"prepare",pkg->info.prepare,NULL}, - {"make",pkg->info.make,NULL}, {"install",pkg->info.install,NULL}, {"special",pkg->info.special,NULL}, {"dependencies",pkg->dependencies,&pkg->dependenciesCount}, {"optional",pkg->optional,&pkg->optionalCount}, - {"description",pkg->info.description,NULL}, + {"description",pkg->description,NULL}, {"locations",pkg->locations,&pkg->locationsCount}, }; @@ -287,7 +294,6 @@ int create(const char* path,struct package* pkg) if (pkg->type != NULL) fprintf(ecmp,"type = %s\n",pkg->type); if (pkg->license != NULL) fprintf(ecmp,"license = %s\n",pkg->license); if (pkg->url != NULL) fprintf(ecmp,"url = %s\n",pkg->url); - if (pkg->sha256 != NULL) fprintf(ecmp,"sha256 = %s\n",pkg->sha256); fprintf(ecmp,"\n"); // for improved readability for (unsigned int i = 0;i < sizeof(list) / sizeof(list[0]);i++ ) diff --git a/include/globals.h b/include/globals.h index f6c2d73..8a3f144 100755 --- a/include/globals.h +++ b/include/globals.h @@ -1,6 +1,7 @@ #include "stdbool.h" -#define QUEUE_MAX 64 +// This is very stupid, but I don't want to work on this right now. +#define QUEUE_MAX 65536 #define MAX_PATH 2048 /* @@ -8,20 +9,12 @@ START OF THE (sort of) CONSTANTS DECALRATIONS (They are not mean to be modified a lot) */ - // enable testing mode extern bool TESTING; -// overwrite file when installing -extern bool OVERWRITE; // enable verbose mode extern bool QUIET; -// Flag for skipping checksum validation -extern bool INSECURE; -// Flag indicating that a user passed either Y or N to be used as default -extern bool OVERWRITE_CHOISE; -// Choise for passing N or Y to a prompt by default -extern char* USER_CHOISE[2]; - -extern char* PACKAGE_QUEUE[QUEUE_MAX]; -extern int QUEUE_COUNT; +// Flag indicating that no inputs are required +extern bool AUTO; +// Package queue +extern struct packages* PACKAGE_QUEUE; diff --git a/include/libspm.h b/include/libspm.h index 4ce64de..5de63f1 100755 --- a/include/libspm.h +++ b/include/libspm.h @@ -3,26 +3,20 @@ #include "cutils.h" #include "globals.h" - - -#define LIBSPM_VERSION 1.000 +#define LIBSPM_VERSION 1.001 #define SOURCE "src" #define BINARY "bin" - - struct cmd { // Commands - char* make; char* test; char* prepare; char* install; char* special; - char* download; - char* description; }; + struct package { // Basic infos @@ -30,10 +24,15 @@ struct package char* type; // for the type at first i used an enum but im lazy and its stupid; char* version; char* license; - char* sha256; char* url; char* environment; + // Internal + char* path; + // + + char* description; + char** files; int filesCount; @@ -42,360 +41,130 @@ struct package char** optional; int optionalCount; + + char ** config; + int configCount; char ** locations; int locationsCount; - - char ** inputs; - int inputsCount; - - char ** exports; - int exportsCount; - - + // cmds struct cmd info; }; -//test -int list_installed(); -int count_installed(); -char** search(char *term, int *num_results); -int update(); -int upgrade(); -void create_links(char build_loc[4096], char dest_loc[4096]); -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); -int add_repo(char* name, char* url); -void clean_install(); - -//end test - -// package info - - -// shared function to be called by external programs - -// This prints the version , its bad -// TODO: Rework this -float version(); - -//# Package manipulation - -// Function to install a package from source with a specific format -/* -Accepts: -- const char* spm_path: Path to the package archive. -- int as_dep: Flag indicating if the package is a dependency. -- const char* format: Specific package format (optional). - -Returns: -- int: An integer indicating the result of the installation. - - 0: Package installed successfully. - - -1: Installation failed. -*/ -// Function to install a package from source with a specific format -/* -Accepts: -- const char* spm_path: Path to the package archive. -- int as_dep: Flag indicating if the package is a dependency. -- const char* format: Specific package format (optional). - -Returns: -- int: An integer indicating the result of the installation. - - 0: Package installed successfully. - - -1: Installation failed. -*/ -int install_package_source(const char* spm_path,int as_dep); -int f_install_package_source(const char* spm_path, int as_dep, char* repo); - -// Function to install a package from a binary archive -/* -Accepts: -- const char* archivePath: Path to the binary archive. -- int as_dep: Flag indicating if the package is a dependency. - -Returns: -- int: An integer indicating the result of the installation. - - 0: Package installed successfully. - - -1: Installation failed. -*/ -int install_package_binary(const char* archivePath, int as_dep, const char* repo); - -// Function to uninstall packages -/* -Accepts: -- char* name: The name of the package to uninstall. - -Returns: -- int: An integer indicating the result of the uninstallation. - - 0: The package was successfully uninstalled. - - -1: An error occurred during the uninstallation. - -Description: -This function is used to uninstall packages. It relies on location data, which contains all the files that were installed by the program. This data is stored in a JSON array inside the package's SPM file in DATA_DIR. The function cycles through all the files in the JSON array and removes them from the system. It also removes the package's entry from the installed packages database. - -Note: -- The variable `DEFAULT_FORMAT` is not defined; you may need to replace it with the correct environment variable or value. For example, you can use `getenv("SOVIET_DEFAULT_FORMAT")` or replace it with a string representing the default format. -- The `INSTALLED_DB` variable is assumed to be defined elsewhere in your code. +struct packages +{ + int count; + int size; + // This should have probably been named 'pkg' or something + // using pkgs->buffer[i].… is not that nice + struct package* buffer; +}; -Please avoid making changes to this code unless there's a critical bug or an important missing feature. -*/ -int uninstall(char* name); +/*for use examples see test.c*/ +/*check.c*/ // Function to check if a package is installed and untouched -/* -Accepts: -- const char* name: The name of the package to be checked. - -Returns: -- int: An integer indicating the result of the check. - - 0: Good, package is installed and fine. - - 1: Package is not installed (Package data file is absent). - - 2: Package is corrupted (package data file is here but with no location info). - - 3: Package is corrupted (Some locations aren't here). -*/ -int check(const char* name); - -// Function to create a binary package from source with input and output formats -/* -Accepts: -- const char* src_path: The path to the source package. -- const char* bin_path: The path where the binary package will be created. -- const char* in_format: The input format (optional). -- const char* out_format: The output format. - -Returns: -- int: An integer indicating the result of the binary package creation. -*/ -int f_create_binary_from_source(const char* src_path,const char* bin_path,const char* in_format,const char* out_format); - -// Function to create a binary package from source -/* -Accepts: -- const char* spm_path: The path to the source package. -- const char* bin_path: The path where the binary package will be created. - -Returns: -- int: An integer indicating the result of the binary package creation. -*/ -int create_binary_from_source(const char* spm_path,const char* bin_path); - -// Function to retrieve a package from a data repository -/* -Accepts: -- struct package* i_pkg: A pointer to a package structure with package details. -- const char* out_path: The local path to save the downloaded package. - -Returns: -- char*: A pointer to the package format or NULL if there's an error. -*/ -char* get(struct package *i_pkg, const char* repo, const char* out_path); - -// Function to move binaries to the correct locations -/* -Accepts: -- char** locations: An array of file locations. -- long loc_size: The number of locations in the array. - -Description: -This function iterates through the given file locations and moves the binaries to their correct destinations. - -Notes: -- It checks if the destination location is empty and moves files from the build directory to the destination. -- If the destination location is not empty, it provides a warning and optionally renames the file in the build directory. - -Returns: None -*/ -void move_binaries(char** locations,long loc_size); -// build a package from source -int make (char* package_dir,struct package* pkg); -// execute post install scripts -int exec_special(const char* cmd,const char* package_dir); - - -// update the system -int update(); +int check(struct package* pkg); +// Function to check the existence of package locations +int check_locations(char** locations, int locationsCount); +/*clean.c*/ // Function to clean working directories -/* -Returns: -- int: An integer indicating the result of the cleaning operation. - - The return value is the sum of the following operations: - - rmrf(build_dir): Removing the build directory and its contents. - - rmrf(make_dir): Removing the make directory and its contents. - - mkdir(build_dir, 0755): Creating the build directory with the specified permissions. - - mkdir(make_dir, 0755): Creating the make directory with the specified permissions. -*/ int clean(); -// Function to synchronize the local repository with a remote repository -int repo_sync(); - -// init the system -void init(); - -// Quit the program with the given status code and display an error message if status is not 0 -/* -Accepts: -- int status: The exit status code. - -Description: -This function exits the program with the specified status code. If the status code is not 0 (indicating an error), it also displays an error message. - -Returns: -- void: This function does not return a value. -*/ -void quit(int status); +// Function to clean unneeded files after install +void clean_install(); +/*config.c*/ +// Read a config file int readConfig(const char* configFilePath, int overwrite); -// Function to check the existence of package locations -/* -Accepts: -- char** locations: An array of strings representing package locations. -- int locationsCount: The number of locations in the array. +/*globals.c*/ +/*see globals.h*/ -Returns: -- int: An integer indicating the result of the check. - - 0: All locations exist, so the package is installed and fine. - - 3: Some locations do not exist, indicating package corruption (some locations are missing). -*/ -int check_locations(char** locations,int locationsCount); +/*hashtable.c*/ +/*see hashtable.h*/ -// Open a package from the given path and populate the package structure -/* -Accepts: -- const char* path: The path to the package file. -- struct package* pkg: A pointer to the package structure to populate. -- const char* format: The format of the package (optional). +/*init.c*/ +// Function to initialize the Soviet Package Manager +void init(); -Description: -This function opens a package from the specified path, reads the package file's format, and populates the provided package structure with its contents. +/*install.c*/ +// Function to install a package from source +int install_package_source(struct package* pkg); +// Function to write the package configuration file +void write_package_configuration_file(struct package* pkg); +// Function to read the package configuration file +void read_package_configuration_file(struct package* pkg); -Returns: -- int: An integer indicating the result of opening the package. - - 0: Package opened successfully. - - 1: File does not exist or is not a valid package file. - - 1: File is not a valid package file or the format plugin isn't loaded. -*/ -int open_pkg(const char* path, struct package* pkg,const char* format); +/*make.c*/ +// Function to build and install a package +int make(struct package* pkg); +/*move.c*/ +// Function to move binaries to the correct locations +void move_binaries(char** locations, long loc_size); + +/*pkg.c*/ +// Allocate an array of packages +struct packages* create_pkgs(int reserve); +// Merge 2 package arrays +void merge_pkgs(struct packages* destination, struct packages* source); +// Free a package array +void free_pkgs(struct packages* pkgs); +// Push a package into the array +void push_pkg(struct packages* pkgs, struct package* pkg); +// Pop the last added package from the array +struct package* pop_pkg(struct packages* pkgs); +// Open a package from the given path and populate the package structure +int open_pkg(const char* path, struct package* pkg); // Create a package at the given path using the specified format and package structure -/* -Accepts: -- const char* path: The path to the package file to be created. -- struct package* pkg: A pointer to the package structure containing package data. -- const char* format: The format of the package (optional). - -Description: -This function creates a package file at the specified path using the provided format and package data from the package structure. - -Returns: -- int: An integer indicating the result of creating the package. - - 0: Package created successfully. - - -1: File is not a valid package file or the format plugin isn't loaded. -*/ -int create_pkg(const char* path,struct package* pkg,const char* format); - -// Load a format plugin, execute a specific function, and close the plugin -/* -Accepts: -- const char* format: The format of the package. -- const char* fn: The name of the function to execute in the format plugin. -- const char* pkg_path: The path to the package file. -- struct package* pkg: A pointer to the package structure. - -Description: -This function loads a format plugin, executes a specified function within the plugin, and then closes the plugin. - -Returns: -- int: An integer indicating the result of running the format plugin. - - 0: Format plugin executed successfully. - - 1: Format plugin file does not exist. - - 1: Error loading or executing the format plugin. - - -1: Format plugin function returned an error. -*/ -int runFormatLib (const char* format,const char* fn,const char* pkg_path,struct package* pkg); - -// Function to get the package name from a binary archive path -/* -Accepts: -- const char* bin_path: Path to the binary package archive. -- char* name: A character array to store the package name. - -Returns: -- int: An integer indicating the result of name extraction. - - 0: Name extracted successfully. - - -1: Extraction failed. -*/ -int get_bin_name(const char* bin_path,char* name); - -// Function to check if a package is already installed -/* -Accepts: -- const char* name: Name of the package to check. - -Returns: -- bool: A boolean value indicating whether the package is installed. - - true: Package is installed. - - false: Package is not installed. -*/ -bool is_installed(const char* name); - +int create_pkg(char* in_path, struct package* pkg); // Function to free memory allocated for a package structure -/* -Accepts: -- struct package* pkg: Pointer to a package structure. - -Returns: -- int: An integer indicating the result of memory deallocation. - - 0: Memory freed successfully. -*/ int free_pkg(struct package* pkg); +// Function to search for packages in the database +struct packages* search_pkgs(char* db_path, char* name); +// Create the database that stores all packages in a directory +int create_pkg_db(char* db_path, struct packages* pkgs); +// Get all packages from a directory +struct packages* get_pkgs(char* path); +// Dump contents of a database to a package array +struct packages* dump_db(char* db_path); +// Function returns an array of packages that need updating +struct packages* update_pkg(); + +/*repo.c*/ +// Get currently present repos +char** get_repos(int* count); +// Function to synchronize the local repository with a remote repository +int repo_sync(); +// Add a new repository from a git repo +int add_repo(char* name, char* url); -// Function to download a file from a given URL and save it to a specified path -/* -Accepts: -- const char* url: The URL of the file to download. -- const char* file_path: The local file path to save the downloaded file. - -Returns: -- int: An integer indicating the result of the download operation. - - 0: Download success. - - -1: Download failure. -*/ -char* load_from_repo(const char* in, const char* repo, const char* file_path); - -// Function to download a repository from a given URL -/* -Accepts: -- const char* url_path: The path to the resource on the repository. -- const char* file_path: The local file path to save the downloaded resource. - -Returns: -- int: An integer indicating the result of the download operation. - - 0: Download success. - - 1: Download failure. -*/ -int loadFile(const char* path, const char* file_path); - -// Function to retrieve file locations within a directory -/* -Accepts: -- char*** locations: Pointer to an array of strings to store file locations. -- const char* loc_dir: Path to the directory to search for files. - -Returns: -- long: The number of file locations retrieved. -*/ -long get_locations(char*** locations, const char* loc_dir); - - - - - - +/*uninstall.c*/ +// Function to uninstall packages +int uninstall(struct package* pkg); +/*util.c*/ +// Recursively remove a directory and its contents +int rmrf(char *path); +// remove a file or link or directory +int rmany(char* path); +// Quit the program with the given status code and display an error message if status is not 0 +void quit(int status); +// Function to recursively retrieve all files in a directory and its subdirectories +char **get_all_files(const char* root, char *path, int *num_files); +// Load a format plugin, execute a specific function, and close the plugin +int runFormatLib(const char* format, const char* fn, const char* pkg_path, struct package* pkg); +// A function to retrieve the version number of the libspm library. +float version(); +// 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); +// Download a file from url into FILE +int download(char* url, FILE* fp); +// Copy a file +int cp(char* from, char* to); +// Ask a yes/no queston +int get_input(char* prompt, int def); diff --git a/lib/cutils b/lib/cutils index a91260e..0d4e262 160000 --- a/lib/cutils +++ b/lib/cutils @@ -1 +1 @@ -Subproject commit a91260eba0df2f622be2389c04ddb0780a703751 +Subproject commit 0d4e2628bc08d3b4a8a25a90375ee1ab561088a5 diff --git a/makefile b/makefile index 9a2f40a..66c04cd 100755 --- a/makefile +++ b/makefile @@ -30,11 +30,12 @@ SDIR = src CFLAGS = -Wall -fPIC -O2 -Wextra -L./bin -Iinclude -DBGFLAGS = -g -fsanitize=address +DBGFLAGS = -g -fsanitize=address -lasan # set local lib to lib/*/*.a LOCAL_LIBS = $(wildcard lib/*/*.a) -LIBS = ${LOCAL_LIBS} -lgit2 -lcurl -lm -lcrypto +LOCAL_LIBS_DIRS = $(wildcard lib/*/) +LIBS = ${LOCAL_LIBS} -lgit2 -lsqlite3 -lcurl -lm -lcrypto # change these to proper directories where each file should be SRCDIR = src @@ -72,8 +73,7 @@ $(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c test: - $(CC) $(CFLAGS) -DSTATIC ${FMT_DIR}/*/* ${DEVDIR}/spm.c ${DEVDIR}/test.c $(LIBS) -o bin/spm-test -lspm -L./bin -D MEMCHECK=$(MEMCHECK) - $(CC) $(CFLAGS) -DSTATIC ${FMT_DIR}/*/* ${DEVDIR}/package.c ${DEVDIR}/test.c $(LIBS) -o bin/package-test -lspm -L./bin -D MEMCHECK=$(MEMCHECK) + $(CC) $(CFLAGS) -lasan -DSTATIC ${FMT_DIR}/*/* ${DEVDIR}/spm.c ${DEVDIR}/test.c $(LIBS) -o bin/spm-test -lspm -L./bin -D MEMCHECK=$(MEMCHECK) @echo "Test binary created" check-all: @@ -91,7 +91,7 @@ debug: libs $(BINDIR)/$(LIBOUT) formats @echo "Build done (debug)" libs: - for i in $(LOCAL_LIBS); do make -C $$(dirname $$i) all; done + for i in $(LOCAL_LIBS_DIRS); do make -C $$i clean all; done direct: $(CC) $(CFLAGS) $(SRCS) $(LIBS) -g -shared -fPIC -o $(BINDIR)/$(LIBOUT) @@ -116,7 +116,4 @@ install: $(BINDIR)/$(LIBOUT) @if [ ! -d $(DESTDIR)/usr/include/spm ]; then mkdir -p $(DESTDIR)/usr/include/spm; fi for i in include/*; do install -vDm 755 $$i $(DESTDIR)/usr/include/spm/; done install -vDm 755 $(BINDIR)/$(LIBOUT) $(DESTDIR)/usr/lib/$(LIBOUT) - install $(BINDIR)/plugins/ecmp.so -vDm 755 $(DESTDIR)/var/cccp/plugins/ecmp.so - - - + install $(BINDIR)/plugins/ecmp.so -vDm 755 $(DESTDIR)/var/cccp/plugins/ecmp.so \ No newline at end of file diff --git a/src/check.c b/src/check.c index 47dc5f1..1c7477d 100755 --- a/src/check.c +++ b/src/check.c @@ -1,7 +1,9 @@ // Include necessary header files for the code #include "libspm.h" // Custom library for package management -#include "unistd.h" // Standard library for system calls -#include "stdio.h" // Standard I/O library for file operations +#include "cutils.h" + +#include // Standard library for system calls +#include // Standard I/O library for file operations #include // Standard library for general functions // Function to check if a package is installed and untouched @@ -16,30 +18,34 @@ - 2: Package is corrupted (package data file is here but with no location info). - 3: Package is corrupted (Some locations aren't here). */ -int check(const char* name) +int check(struct package* pkg) { - char dataSpmPath[MAX_PATH]; - // Create the path to the package data file using environment variables - sprintf(dataSpmPath, "%s/%s", getenv("SOVIET_SPM_DIR"), name); + dbg(2, "Creating a path to the local package"); + + char dataSpmPath[MAX_PATH]; + sprintf(dataSpmPath, "%s/%s", getenv("SOVIET_SPM_DIR"), pkg->path); + dbg(2, "PATH: %s", dataSpmPath); // Checking if the package data file exists if (access(dataSpmPath, F_OK) != 0) { + dbg(2, "PATH does not exist"); return 1; // Exit code 1 indicates the package is not installed } - struct package pkg; - // Open the package data file and load its contents - open_pkg(dataSpmPath, &pkg, getenv("SOVIET_DEFAULT_FORMAT")); + dbg(2, "Opening the package"); + open_pkg(getenv("SOVIET_SPM_DIR"), pkg); + dbg(2, "Checking package locations"); // If the package data file lacks location information, return exit code 2 - if (pkg.locationsCount == 0) { + if (pkg->locationsCount == 0) { + dbg(2, "The package is corrupted"); return 2; // Exit code 2 indicates the package is corrupted (no location info) } // Check the existence of package locations and return the appropriate exit code - return check_locations(pkg.locations, pkg.locationsCount); + return check_locations(pkg->locations, pkg->locationsCount); } // Function to check the existence of package locations @@ -58,6 +64,7 @@ int check_locations(char** locations, int locationsCount) for (int i = 0; i < locationsCount; i++) { // If a location doesn't exist, return exit code 3 if (access(locations[i], F_OK) != 0) { + dbg(2, "The package is corrupted (some locations are missing)"); return 3; // Exit code 3 indicates the package is corrupted (some locations are missing) } } diff --git a/src/clean.c b/src/clean.c index a2edb39..58ef710 100755 --- a/src/clean.c +++ b/src/clean.c @@ -1,4 +1,5 @@ #include "cutils.h" // Custom utility library +#include "libspm.h" #include // Standard library for general functions #include // Standard library for file status information @@ -34,11 +35,10 @@ void clean_install() for(int i = 0; i < count; i++) { - struct stat st; char* full_cleanup_path = calloc(strlen(build_dir) + strlen(cleanup_loc[i]) + 2, 1); snprintf(full_cleanup_path, strlen(build_dir) + strlen(cleanup_loc[i]) + 1, "%s%s", build_dir, cleanup_loc[i]); - if(strstr(full_cleanup_path, "/.") != NULL) + if(strstr(full_cleanup_path, "/..") != NULL) { dbg(1, "path %s is sus", full_cleanup_path); } @@ -46,24 +46,11 @@ void clean_install() { dbg(1, "deleting %s", full_cleanup_path); - if (lstat(full_cleanup_path, &st) != 0) - { - dbg(2, "Error getting file info"); - } - else - { - if (S_ISDIR(st.st_mode)) - { - dbg(2, "%s is a dir", full_cleanup_path); - rmrf(full_cleanup_path); - } - - if (S_ISREG(st.st_mode)) - { - dbg(2, "%s is a file", full_cleanup_path); - remove(full_cleanup_path); - } - } + rmany(full_cleanup_path); } + free(cleanup_loc[i]); + free(full_cleanup_path); } + free(cleanup_loc); + free(cleanups); } \ No newline at end of file diff --git a/src/config.c b/src/config.c index 813ac8b..b5abaa4 100755 --- a/src/config.c +++ b/src/config.c @@ -8,8 +8,6 @@ #include -#define DEFAULT_CONFIG_FILE "/etc/cccp.conf" // Default config file path - // A hashmap to store config values with default values typedef struct { const char* key; @@ -17,24 +15,27 @@ typedef struct { } ConfigEntry; ConfigEntry configEntries[] = { - { "SOVIET_ROOT", "/" }, - { "SOVIET_DEFAULT_FORMAT", "ecmp" }, - { "SOVIET_MAIN_DIR", "/var/cccp" }, - { "SOVIET_WORK_DIR", "/var/cccp/work" }, - { "SOVIET_CONFIG_FILE", DEFAULT_CONFIG_FILE }, - { "SOVIET_REPOS_DIR", "/var/cccp/sources" }, - { "SOVIET_SPM_DIR", "/var/cccp/spm" }, - { "SOVIET_LOG_DIR", "/var/cccp/log" }, - { "SOVIET_PLUGIN_DIR", "/var/cccp/plugins" }, - { "SOVIET_BUILD_DIR", "/var/cccp/work/build" }, - { "SOVIET_MAKE_DIR", "/var/cccp/work/make" }, - { "MAKE_FLAGS", "-j1" }, - { "SOVIET_DEFAULT_REPO", "OUR" }, - { "SOVIET_DEFAULT_REPO_URL", "https://github.com/Soviet-Linux/OUR.git" }, - { "SOVIET_FORMATS", "ecmp" }, - { "SOVIET_SOURCE_DIR", "/usr/src/cccp" }, - { "SOVIET_ENV_DIR", "/etc/cccp" }, - { "SOVIET_CLEANUP", "/usr/share/info/dir:/usr/share/doc/" }, + { "SOVIET_ROOT" , "/" }, + { "SOVIET_USER_ROOT" , "~/.local/" }, + { "SOVIET_DEFAULT_FORMAT" , "ecmp" }, + { "SOVIET_MAIN_DIR" , "/var/cccp" }, + { "SOVIET_WORK_DIR" , "/var/cccp/work" }, + { "SOVIET_CONFIG_FILE" , "/etc/cccp.conf" }, + { "SOVIET_REPOS_DIR" , "/var/cccp/sources" }, + { "SOVIET_SPM_DIR" , "/var/cccp/spm" }, + { "SOVIET_LOG_DIR" , "/var/cccp/log" }, + { "SOVIET_PLUGIN_DIR" , "/var/cccp/plugins" }, + { "SOVIET_BUILD_DIR" , "/var/cccp/work/build" }, + { "SOVIET_MAKE_DIR" , "/var/cccp/work/make" }, + { "SOVIET_DEFAULT_REPO" , "OUR" }, + { "SOVIET_DEFAULT_REPO_URL" , "https://github.com/Soviet-Linux/OUR.git" }, + { "SOVIET_FORMATS" , "ecmp" }, + { "SOVIET_SOURCE_DIR" , "/usr/src/cccp" }, + { "SOVIET_ENV_DIR" , "/etc/cccp" }, + { "SOVIET_CLEANUP" , "/usr/share/info/dir:/usr/share/doc/" }, + { "SOVIET_ALL_DB" , "/var/cccp/all.db" }, + { "SOVIET_INSTALLED_DB" , "/var/cccp/installed.db" }, + { "MAKE_FLAGS" , "-j1" }, // Add more key-value pairs with default values as needed }; @@ -44,10 +45,9 @@ const size_t numConfigEntries = sizeof(configEntries) / sizeof(configEntries[0]) int readConfig(const char* configFilePath, int overwrite) { if (configFilePath == NULL) { - configFilePath = DEFAULT_CONFIG_FILE; // Use the default config file path + msg(FATAL, "Tried to use non-existing config"); } - dbg(2, "config: %s", configFilePath); dbg(2, "config: %s", configFilePath); FILE* file = fopen(configFilePath, "r"); dbg(2, "file is readed"); @@ -77,13 +77,17 @@ int readConfig(const char* configFilePath, int overwrite) char* line = calloc(1024, 1); while (fgets(line, 1024, file)) { - line[strlen(line) - 1] = 0; + line[strlen(line)] = 0; parse_env(&line); if(((line[0] != '#') && ((line[0] != '/') && (line[1] != '/'))) && (strstr(line, "=") != 0)) { char* key = strtok(line, "="); char* value = strchr(line, '\0') + 1; + if(strchr(value, '\n') != NULL) + { + value[strlen(value) - strlen(strchr(value, '\n'))] = '\0'; + } if (key == NULL || value == NULL) { msg(ERROR, "Invalid config file"); @@ -107,6 +111,5 @@ int readConfig(const char* configFilePath, int overwrite) setenv(configEntries[i].key, configEntries[i].default_value, overwrite); } } - return 0; } diff --git a/src/create.c b/src/create.c deleted file mode 100644 index 40d1c83..0000000 --- a/src/create.c +++ /dev/null @@ -1,105 +0,0 @@ -#include // Standard I/O library for file operations -#include // Standard library for general functions -#include // Standard library for string manipulation - -#include "libspm.h" // Custom library for package management -#include "cutils.h" // Custom utility library - -// Function prototype for creating an archive from a directory -int create_archive(const char* DIR, const char* out_path); - -// Function to create a binary package from source -/* -Accepts: -- const char* spm_path: The path to the source package. -- const char* bin_path: The path where the binary package will be created. - -Returns: -- int: An integer indicating the result of the binary package creation. -*/ -int create_binary_from_source(const char* spm_path, const char* bin_path) { - return f_create_binary_from_source(spm_path, bin_path, NULL, getenv("SOVIET_DEFAULT_FORMAT")); -} - -// Function to create a binary package from source with input and output formats -/* -Accepts: -- const char* src_path: The path to the source package. -- const char* bin_path: The path where the binary package will be created. -- const char* in_format: The input format (optional). -- const char* out_format: The output format. - -Returns: -- int: An integer indicating the result of the binary package creation. -*/ -int f_create_binary_from_source(const char* src_path, const char* bin_path, const char* in_format, const char* out_format) -{ - struct package pkg; - - // Open the package source - open_pkg(src_path, &pkg, NULL); - - PACKAGE_QUEUE[QUEUE_COUNT] = pkg.name; // Add the package name to the PKG_QUEUE ARRAY - QUEUE_COUNT++; - dbg(1, "Added %s at QUEUE[%d] ", pkg.name, QUEUE_COUNT); - - /* - Here we have some problems: - The legacy package directory was in MAKE_DIR/$NAME-$VERSION - Should we keep it or not? - I choose, for compatibility reasons, to keep it. - If someone wants to change this, you can vote here: - - keep it: 1 - - change it: 0 - */ - const char* MAKE_DIR = getenv("SOVIET_MAKE_DIR"); - const char* BUILD_DIR = getenv("SOVIET_BUILD_DIR"); - - char legacy_dir[MAX_PATH]; - sprintf(legacy_dir, "%s/%s-%s", MAKE_DIR, pkg.name, pkg.version); - dbg(1, "legacy dir: %s", legacy_dir); - - // Make the package - if (make(legacy_dir, &pkg) != 0) { - msg(FATAL, "Make failed"); - } - dbg(1, "Make done - %s", pkg.name); - - // Get package locations - dbg(1, "Getting locations - %s", pkg.name); - pkg.locationsCount = get_locations(&pkg.locations, BUILD_DIR); - - char file_path[MAX_PATH]; - sprintf(file_path, "%s/%s.%s", BUILD_DIR, pkg.name, getenv("SOVIET_DEFAULT_FORMAT")); - - // Create a package file - create_pkg(file_path, &pkg, NULL); - - // Compress binaries to a package archive - dbg(1, "Compressing binaries - %s", pkg.name); - create_archive(BUILD_DIR, bin_path); - - // Clean working directories - clean(); - - return 0; -} - -// Function to create an archive from a directory -/* -Accepts: -- const char* DIR: The directory to be archived. -- const char* out_path: The path where the archive file will be created. - -Returns: -- int: An integer indicating the result of the archive creation. -*/ -int create_archive(const char* DIR, const char* out_path) -{ - char* archive_cmd = calloc(256, sizeof(char)); - sprintf(archive_cmd, "( cd %s && tar -czf %s . )", DIR, out_path); - dbg(1, "archive_cmd: %s", archive_cmd); - int EXIT = system(archive_cmd); - free(archive_cmd); - return EXIT; -} diff --git a/src/download.c b/src/download.c deleted file mode 100644 index abe3e26..0000000 --- a/src/download.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "math.h" -#include -#include -#include - -#include - -// Include necessary headers - -// class stuff -#include "libspm.h" -#include "cutils.h" - -int download(char* url, FILE* fp) { - CURL *curl = curl_easy_init(); - if(curl) { - CURLcode res; - (void) res; - curl_easy_setopt(curl, CURLOPT_USERAGENT, "CCCP/1.0 (https://www.sovietlinux.org/)"); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - } - return 0; -} diff --git a/src/environment.c b/src/environment.c deleted file mode 100644 index 104c8d7..0000000 --- a/src/environment.c +++ /dev/null @@ -1,90 +0,0 @@ -#include "stdio.h" -#include -#include - -#include "libspm.h" -#include "globals.h" -#include "cutils.h" - -#include - -// 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; - - 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); - char* dup_in = calloc(start_i + 1, 1); - if(start_i != 0) - { - snprintf(dup_in, start_i + 1, "%s", *in); - } - var[--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); - - sprintf(full_in, "%s%s%s", dup_in, full_var, end); - - free(*in); - free(dup_in); - free(var); - *in = full_in; - - dbg(2, "Result: %s", *in); - - return parse_env(in); -} \ No newline at end of file diff --git a/src/globals.c b/src/globals.c index 3ad4af1..65fef89 100644 --- a/src/globals.c +++ b/src/globals.c @@ -1,32 +1,17 @@ // Include necessary headers #include "stdbool.h" +#include "libspm.h" #include #include "cutils.h" #include "globals.h" -// Define a constant for the maximum queue size -#define QUEUE_MAX 64 - // Declare global variables // Flag for testing mode bool TESTING = false; -// Flag for overwriting files -bool OVERWRITE = false; - // Flag for quiet mode (no verbose output) bool QUIET = true; -// Flag for skipping checksum validation -bool INSECURE = false; - -// Flag indicating that a user passed either Y or N to be used as default -bool OVERWRITE_CHOISE = false; - -// Choise for passing N or Y to a prompt by default -char* USER_CHOISE[2]; - -// Array for package queue and its count -char* PACKAGE_QUEUE[QUEUE_MAX]; -int QUEUE_COUNT; +// Flag indicating that no inputs are required +bool AUTO = false; diff --git a/src/init.c b/src/init.c index 87a6059..8b6ffa5 100755 --- a/src/init.c +++ b/src/init.c @@ -51,6 +51,7 @@ void init() { msg(ERROR, "Format plugin %s not found", format); exit(1); } + free(formats[i]); } //free(*formats); diff --git a/src/install.c b/src/install.c index 9cf90d5..c7462b2 100755 --- a/src/install.c +++ b/src/install.c @@ -13,492 +13,222 @@ // include header for wait() #include -// Function to install a package from source (archive) -/* -Accepts: -- const char* spm_path: Path to the package archive. -- int as_dep: Flag indicating if the package is a dependency. - -Returns: -- int: An integer indicating the result of the installation. - - 0: Package installed successfully. - - -1: Installation failed. -*/ -int install_package_source(const char* spm_path, int as_dep) { - return f_install_package_source(spm_path, as_dep, NULL); -} - // Function to install a package from source with a specific format /* Accepts: - const char* spm_path: Path to the package archive. -- int as_dep: Flag indicating if the package is a dependency. -- const char* format: Specific package format (optional). Returns: - int: An integer indicating the result of the installation. - 0: Package installed successfully. - -1: Installation failed. */ -int f_install_package_source(const char* spm_path, int as_dep, char* repo) { - // Check if spm_path is NULL - - if (spm_path == NULL) { - msg(ERROR, "spm_path is NULL"); - return -1; - } - +int install_package_source(struct package* pkg) +{ // Get required directory paths - char* make_dir = getenv("SOVIET_MAKE_DIR"); - char* build_dir = getenv("SOVIET_BUILD_DIR"); - - if (make_dir == NULL || build_dir == NULL) { - msg(ERROR, "SOVIET_MAKE_DIR or SOVIET_BUILD_DIR is not set"); - return -1; - } - - // Initialize the package structure - struct package pkg = {0}; - - char* format = "ecmp"; - - // Attempt to open the package archive - if (open_pkg(spm_path, &pkg, format) != 0) { - msg(ERROR, "Failed to open package"); - return -1; - } - - msg(INFO, "Installing %s", pkg.name); - - // Add the package name to the queue - PACKAGE_QUEUE[QUEUE_COUNT] = pkg.name; - QUEUE_COUNT++; - dbg(1, "Added %s to the queue", pkg.name); - - // Set the package info section as environment vadiables for make script - setenv("NAME", pkg.name, 1); - setenv("VERSION", pkg.version, 1); - - if (pkg.url != NULL) - { - parse_env(&(pkg.url)); - dbg(1, "URL: %s", pkg.url); - setenv("URL", pkg.url, 1); - } - - if (pkg.type != NULL) - { - setenv("TYPE", pkg.type, 1); - } - - if (pkg.license != NULL) - { - setenv("LICENSE", pkg.license, 1); - } - - if (pkg.sha256 != NULL) { - setenv("SHA256", pkg.sha256, 1); + char* make_dir = getenv("SOVIET_MAKE_DIR"); + char* build_dir = getenv("SOVIET_BUILD_DIR"); + + if (make_dir == NULL || build_dir == NULL) + { + msg(ERROR, "SOVIET_MAKE_DIR or SOVIET_BUILD_DIR is not set"); + return -1; + } } - // Set environment variables for building - setenv("BUILD_ROOT", build_dir, 1); + msg(INFO, "Installing %s", pkg->name); - /* Warning: there is something sussy going on beyond this point */ - - // Get global environment variables - if (pkg.environment != NULL) - { - dbg(1, "Getting environment variables..."); - char* env_path = calloc(MAX_PATH, 1); - sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg.environment); - - readConfig(env_path, 1); - } - - // Set global environment variables - if (pkg.exports != NULL && pkg.exportsCount > 0 && strlen(pkg.exports[0]) > 0) + // Set the package info section as environment vadiables for make script { - dbg(1, "Setting environment variables..."); - char* env_path = calloc(MAX_PATH, 1); - sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg.name); - - FILE *env_file; - env_file = fopen(env_path, "w"); + dbg(2, "%s", pkg->name); + setenv("NAME", pkg->name, 1); + dbg(2, "%s", pkg->version); + setenv("VERSION", pkg->version, 1); + + if (pkg->url != NULL) + { + parse_env(&(pkg->url)); + dbg(1, "URL: %s", pkg->url); + setenv("URL", pkg->url, 1); + } - for (int i = 0; i < pkg.exportsCount; i++) + if (pkg->type != NULL) { - fprintf(env_file, "%s\n", pkg.exports[i]); - char* line = strdup(pkg.exports[i]); - parse_env(&line); - - if(((line[0] != '#') && ((line[0] != '/') && (line[1] != '/'))) && (strstr(line, "=") != 0)) - { - char* key = strtok(line, "="); - char* value = strchr(line, '\0') + 1; - - if (key == NULL || value == NULL) - { - msg(ERROR, "Invalid config file"); - } - - dbg(2, "Key: %s Value: %s", key, value); - - // Set environment variables based on the key-value pairs in the config file - setenv(key, value, 1); - } - free(line); + setenv("TYPE", pkg->type, 1); } - fclose(env_file); + if (pkg->license != NULL) + { + setenv("LICENSE", pkg->license, 1); + } } - // Check if a package is a collection - if(strcmp(pkg.type, "con") != 0) + if(strcmp(pkg->type, "con") != 0) { // Legacy directory path for compatibility char legacy_dir[MAX_PATH]; - sprintf(legacy_dir, "%s/%s-%s", getenv("SOVIET_MAKE_DIR"), pkg.name, pkg.version); - - // ... - chmod(getenv("SOVIET_MAKE_DIR"), 0777); - chmod(getenv("SOVIET_BUILD_DIR"), 0777); + sprintf(legacy_dir, "%s/%s-%s", getenv("SOVIET_MAKE_DIR"), pkg->name, pkg->version); - pid_t p = fork(); - int status = 0; - if ( p == 0) + // Build the package { + // ... + chmod(getenv("SOVIET_MAKE_DIR"), 0777); + chmod(getenv("SOVIET_BUILD_DIR"), 0777); - if (getuid() == 0) + pid_t p = fork(); + int status = 0; + if ( p == 0) { - /* process is running as root, drop privileges */ - if (setgid(65534) != 0) + // Ensure that the build is done as a regular user { - msg(ERROR, "setgid: Unable to drop group privileges"); - } - if (setuid(65534) != 0) - { - msg(ERROR, "setuid: Unable to drop user privileges"); + if (getuid() == 0) + { + // process is running as root, drop privileges + if (setgid(65534) != 0) + { + msg(ERROR, "setgid: Unable to drop group privileges"); + } + if (setuid(65534) != 0) + { + msg(ERROR, "setuid: Unable to drop user privileges"); + } + } } + + // Build the package + dbg(1, "Making %s", pkg->name); + make(pkg); + exit(0); + } + else + { + waitpid(p, &status, 0); + } + + if(WIFSIGNALED(status)) + { + msg(FATAL, "WIFSIGNALED"); } - // Build the package - dbg(1, "Making %s", pkg.name); - if (make(legacy_dir, &pkg) != 0) { - msg(ERROR, "Failed to make %s", pkg.name); - exit(1); + if(WEXITSTATUS(status) != 0) + { + msg(FATAL, "make exited with error code %d", WEXITSTATUS(status)); } - exit(0); - } - while(wait(&status) > 0); - if(WEXITSTATUS(status) != 0) - { - msg(FATAL, "make exited with error code %d", pkg.name, status); + dbg(1, "Making %s done", pkg->name); } - dbg(1, "Making %s done", pkg.name); - // Run 'install' command - if (pkg.info.install == NULL && strlen(pkg.info.install) == 0) { - msg(FATAL, "No install command!"); - } + { + if (pkg->info.install == NULL && strlen(pkg->info.install) == 0) { + msg(FATAL, "No install command!"); + } - char install_cmd[64 + strlen(legacy_dir) + strlen(pkg.info.install)]; - sprintf(install_cmd, "( cd %s && %s )", legacy_dir, pkg.info.install); + char install_cmd[64 + strlen(legacy_dir) + strlen(pkg->info.install)]; + sprintf(install_cmd, "( cd %s && %s )", legacy_dir, pkg->info.install); - dbg(2, "Executing install command: %s", install_cmd); - if (system(install_cmd) != 0) { - msg(FATAL, "Failed to install %s", pkg.name); - return -2; + dbg(2, "Executing install command: %s", install_cmd); + if (system(install_cmd) != 0) { + msg(FATAL, "Failed to install %s", pkg->name); + return -2; + } + clean_install(); + dbg(1, "Install command executed!"); } - clean_install(); - dbg(1, "Install command executed!"); - // Get package locations - dbg(1, "Getting locations for %s", pkg.name); - pkg.locationsCount = get_locations(&pkg.locations, getenv("SOVIET_BUILD_DIR")); - - if (pkg.locationsCount <= 0) { - msg(ERROR, "Failed to get locations for %s", pkg.name); - return -1; - } + { + dbg(1, "Getting locations for %s", pkg->name); + pkg->locations = get_all_files(getenv("SOVIET_BUILD_DIR") + 1, getenv("SOVIET_BUILD_DIR"), &(pkg->locationsCount)); + + if (pkg->locationsCount <= 0) { + msg(ERROR, "Failed to get locations for %s", pkg->name); + return -1; + } - dbg(1, "Got %d locations for %s", pkg.locationsCount, pkg.name); + dbg(1, "Got %d locations for %s", pkg->locationsCount, pkg->name); - // Check if the package is already installed - if (is_installed(pkg.name)) { - msg(WARNING, "Package %s is already installed, reinstalling", pkg.name); - uninstall(pkg.name); - } else { - dbg(3, "Package %s is not installed", pkg.name); - } + // Check if the package is already installed + if (check(pkg) == 0) { + msg(WARNING, "Package %s is already installed, reinstalling", pkg->name); + uninstall(pkg); + } else { + dbg(3, "Package %s is not installed", pkg->name); + } - // Move binaries to their destination - dbg(1, "Moving binaries for %s", pkg.name); - move_binaries(pkg.locations, pkg.locationsCount); + // Move binaries to their destination + dbg(1, "Moving binaries for %s", pkg->name); + move_binaries(pkg->locations, pkg->locationsCount); + } } // Execute post-install scripts - if (pkg.info.special != NULL && strlen(pkg.info.special) > 0) { - msg(WARNING, "Special: %s", pkg.info.special); - dbg(1, "Executing post install script for %s", pkg.name); - exec_special(pkg.info.special, getenv("SOVIET_BUILD_DIR")); - } - - // Format the path using sprintf - char file_path[MAX_PATH]; - - if(!repo) - { - repo = "local"; - } - - dbg(1, "spm dir is %s", getenv("SOVIET_SPM_DIR")); - dbg(1, "repo is %s", repo); - dbg(1, "name is %s", pkg.name); - dbg(1, "description is %s", pkg.info.description); - - - char repo_path[MAX_PATH]; - sprintf(repo_path, "%s/%s", getenv("SOVIET_SPM_DIR"), repo); - - if(isdir(repo_path) != 0) { - pmkdir(repo_path); - } - - sprintf(file_path, "%s/%s/%s.%s", getenv("SOVIET_SPM_DIR"), repo, pkg.name, getenv("SOVIET_DEFAULT_FORMAT")); - create_pkg(file_path, &pkg, NULL); - dbg(1, "Package %s installed", pkg.name); - - // Clean up - clean(); - - // Remove the package from the queue - QUEUE_COUNT--; - PACKAGE_QUEUE[QUEUE_COUNT] = NULL; - - // Free allocated memory - free_pkg(&pkg); - return 0; -} - -// Utilities declaration for binary install -// Untar a binary package to another directory -/* -Accepts: -- const char* bin_path: Path to the binary package archive. -- const char* dest_dir: Destination directory for untarring. - -Returns: -- int: An integer indicating the result of the untarring. - - 0: Untarring completed successfully. - - Non-zero: An error occurred during untarring. -*/ -__attribute__((unused)) int uncompress_binary(const char* bin_path, const char* dest_dir); - -// Function to install a package from a binary archive -/* -Accepts: -- const char* archivePath: Path to the binary archive. -- int as_dep: Flag indicating if the package is a dependency. - -Returns: -- int: An integer indicating the result of the installation. - - 0: Package installed successfully. - - -1: Installation failed. -*/ -int install_package_binary(const char* archivePath, int as_dep, const char* repo) { - - struct package pkg; - - // Get required environment variables - char* default_format = getenv("SOVIET_DEFAULT_FORMAT"); - char* build_dir = getenv("SOVIET_BUILD_DIR"); - char* spm_dir = getenv("SOVIET_SPM_DIR"); - - if (default_format == NULL || build_dir == NULL || spm_dir == NULL) { - msg(ERROR, "Environment variables not set"); - return -1; - } - - // Initialize package name - pkg.name = calloc(sizeof(archivePath), sizeof(char)); - - // Get the package name from the binary archive - if (get_bin_name(archivePath, pkg.name) != 0) { - msg(ERROR, "Could not get name from archive path"); - return -1; - } - - // Uncompress binary and check the output - if (uncompress_binary(archivePath, build_dir) != 0) - return -1; - - // Format the path using sprintf - char spm_path[MAX_PATH]; - sprintf(spm_path, "%s/%s.%s", build_dir, pkg.name, default_format); - if (access(spm_path, F_OK) != 0) { - msg(ERROR, "%s not found", spm_path); - return -1; + if (pkg->info.special != NULL && strlen(pkg->info.special) > 0) + { + dbg(1, "Executing post install script for %s", pkg->name); + if (system(pkg->info.special) != 0) + { + msg(FATAL, "Failed to run post-install script for %s", pkg->name); + return -2; + } + } } - // Open the package - open_pkg(spm_path, &pkg, NULL); - - // Add the package name to the queue - PACKAGE_QUEUE[QUEUE_COUNT] = pkg.name; - QUEUE_COUNT++; - dbg(1, "Added %s to QUEUE[%d]", pkg.name, QUEUE_COUNT - 1); - - // Move binaries to their destination - dbg(1, "Moving binaries for %s", pkg.name); - move_binaries(pkg.locations, pkg.locationsCount); - - // Execute post-install scripts - exec_special(pkg.info.special, build_dir); - - // Format the path using sprintf - char file_path[MAX_PATH]; - sprintf(file_path, "%s/%s/%s.%s", getenv("SOVIET_SPM_DIR"), repo, pkg.name, getenv("SOVIET_DEFAULT_FORMAT")); - create_pkg(file_path, &pkg, NULL); - - dbg(1, "Package %s installed", pkg.name); - - free_pkg(&pkg); + if(create_pkg(getenv("SOVIET_SPM_DIR"), pkg) != 0) return 1; + dbg(1, "Package %s installed", pkg->name); + // Clean up clean(); - - // Remove the package from the queue - QUEUE_COUNT--; - PACKAGE_QUEUE[QUEUE_COUNT] = NULL; - return 0; } -// Function to check if a package is already installed -/* -Accepts: -- const char* name: Name of the package to check. - -Returns: -- bool: A boolean value indicating whether the package is installed. - - true: Package is installed. - - false: Package is not installed. -*/ -bool is_installed(const char* name) { - char path[1024]; - char** FORMATS; - int FORMAT_COUNT = splita(strdup(getenv("SOVIET_FORMATS")),' ',&FORMATS); - - char** REPOS = calloc(512,sizeof(char)); - int REPO_COUNT = get_repos(REPOS); - - // loop through all formats - for (int i = 0; i < FORMAT_COUNT; i++) +/* Warning: there is something sussy going on beyond this point */ +void write_package_configuration_file(struct package* pkg) +{ + // Set global environment variables + if (pkg->config != NULL && pkg->configCount > 0 && strlen(pkg->config[0]) > 0) { - // loop through all repos - for (int j = 0; j < REPO_COUNT; j++) - { - sprintf(path,"%s/%s/%s.%s",getenv("SOVIET_SPM_DIR"), REPOS[j],name,FORMATS[i]); - if (access(path,F_OK) == 0) - { - free(REPOS); - free(FORMATS); - return true; - } - } - } - return false; -} + dbg(1, "Setting environment variables..."); + char* env_path = calloc(MAX_PATH, 1); + sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg->name); -// Function to get the package name from a binary archive path -/* -Accepts: -- const char* bin_path: Path to the binary package archive. -- char* name: A character array to store the package name. + FILE *env_file; + env_file = fopen(env_path, "w"); -Returns: -- int: An integer indicating the result of name extraction. - - 0: Name extracted successfully. - - -1: Extraction failed. -*/ -int get_bin_name(const char* bin_path, char* name) { - const char* file_name = strrchr(bin_path, '/'); - if (file_name == NULL) - file_name = bin_path; - else - file_name++; - for (int i = 0; i < (int)strlen(file_name); i++) { - if (file_name[i] == '.') { - sprintf(name, "%.*s", i, file_name); - return 0; + for (int i = 0; i < pkg->configCount; i++) + { + fprintf(env_file, "%s\n", pkg->config[i]); } + fclose(env_file); + free(env_path); } - return -1; } -// Function to free memory allocated for a package structure -/* -Accepts: -- struct package* pkg: Pointer to a package structure. +void read_package_configuration_file(struct package* pkg) +{ + // Get global environment variables + if (pkg->environment != NULL) + { + dbg(1, "Getting environment variables..."); + char* env_path = calloc(MAX_PATH, 1); + sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg->environment); -Returns: -- int: An integer indicating the result of memory deallocation. - - 0: Memory freed successfully. -*/ -int free_pkg(struct package* pkg) { - if (pkg->name != NULL) free(pkg->name); - if (pkg->version != NULL) free(pkg->version); - if (pkg->license != NULL) free(pkg->license); - if (pkg->type != NULL) free(pkg->type); - if (pkg->url != NULL) free(pkg->url); - - if (pkg->info.make != NULL) free(pkg->info.make); - if (pkg->info.special != NULL) free(pkg->info.special); - if (pkg->info.download != NULL) free(pkg->info.download); - if (pkg->info.install != NULL) free(pkg->info.install); - if (pkg->info.prepare != NULL) free(pkg->info.prepare); - if (pkg->info.test != NULL) free(pkg->info.test); - - if (pkg->locations) { - if (*pkg->locations) free(*pkg->locations); - free(pkg->locations); - } - if (pkg->dependencies) { - if (*pkg->dependencies) free(*pkg->dependencies); - free(pkg->dependencies); - } - if (pkg->optional) { - if (*pkg->optional) free(*pkg->optional); - free(pkg->optional); - } - if (pkg->files) { - if (*pkg->files) free(*pkg->files); - free(pkg->files); + readConfig(env_path, 1); + free(env_path); } - return 0; -} -// Function to untar a binary package to a destination directory -/* -Accepts: -- const char* bin_path: Path to the binary package archive. -- const char* dest_dir: Destination directory for untarring. -Returns: -- int: An integer indicating the result of untarring. - - 0: Untarring completed successfully. - - Non-zero: An error occurred during untarring. -*/ -int uncompress_binary(const char* bin_path, const char* dest_dir) { - // Format the untar command using sprintf - char untar_cmd[strlen(bin_path) + strlen(dest_dir) + 64]; - sprintf(untar_cmd, "tar -xvf %s -C %s", bin_path, dest_dir); + // Set global environment variables + if (pkg->config != NULL && pkg->configCount > 0 && strlen(pkg->config[0]) > 0) + { + dbg(1, "Setting environment variables..."); + char* env_path = calloc(MAX_PATH, 1); + sprintf(env_path, "%s/%s", getenv("SOVIET_ENV_DIR"), pkg->name); - // Execute the untar command - return system(untar_cmd); -} + readConfig(env_path, 1); + free(env_path); + } +} \ No newline at end of file diff --git a/src/list.c b/src/list.c deleted file mode 100644 index 00df5b6..0000000 --- a/src/list.c +++ /dev/null @@ -1,209 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -// Include necessary headers -#include "libspm.h" -#include "cutils.h" - -#define MAX_PATH_LENGTH 1024 -#define OPEN_ERROR -1 -#define READ_ERROR -2 - -// Function to recursively retrieve all files in a directory and its subdirectories -char **get_all_files(const char* root, const char *path, int *num_files) { - DIR *dir; - struct dirent *entry; - struct stat stat_buf; - char* origin = strdup(path); - // Open the directory - dir = opendir(path); - if (dir == NULL) { - // Print an error message if directory couldn't be opened - fprintf(stderr, "Error opening directory %s: %s\n", path, strerror(errno)); - free(origin); - return NULL; - } - - // Initialize variables - char **files_array = NULL; - int file_count = 0; - - // Loop through directory entries - while ((entry = readdir(dir)) != NULL) { - // Skip '.' and '..' entries - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - - // Construct full path of the current entry - char full_path[MAX_PATH_LENGTH]; - snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); - - // Get information about the current entry - if (stat(full_path, &stat_buf) == 0) { - // If it's a directory, recursively call get_all_files - if (S_ISDIR(stat_buf.st_mode)) { - struct stat dir_stat_buf; - if (lstat(full_path, &dir_stat_buf) == 0) { - // Check if a directory is a symlink (this can probably be optimized out) - if (!S_ISLNK(dir_stat_buf.st_mode)) { - // If it isn't - treat it as a directory - int sub_files_count; - char **sub_files = get_all_files(root, full_path, &sub_files_count); - if (sub_files != NULL) { - // Resize files_array and copy contents of sub_files into it - files_array = realloc(files_array, (file_count + sub_files_count) * sizeof(char *)); - for (int i = 0; i < sub_files_count; i++) { - files_array[file_count++] = sub_files[i]; - } - free(sub_files); - } - } - else { - // If it is - treat it as a file - files_array = realloc(files_array, (file_count + 1) * sizeof(char *)); - files_array[file_count] = strdup(full_path + strlen(root) + 1); - file_count++; - } - } - } else if (S_ISREG(stat_buf.st_mode)) { - // If it's a regular file, add it to files_array - files_array = realloc(files_array, (file_count + 1) * sizeof(char *)); - files_array[file_count] = strdup(full_path + strlen(root) + 1); - file_count++; - } - } - } - // Close the directory - closedir(dir); - - // Update num_files if it's not NULL - if (num_files != NULL) - *num_files = file_count; - - // Return the array of file paths - free(origin); - - return files_array; -} - -// Function to count the number of installed packages -int count_installed() { - const char *path = getenv("SOVIET_SPM_DIR"); - int num_files; - char **files_array = get_all_files(path, path, &num_files); - if (files_array != NULL) { - // Return the number of files - return num_files; - } else { - // If no files found, print a message - printf("No files found.\n"); - } - return 1; -} - -// Function to list all installed packages -int list_installed() { - const char *path = getenv("SOVIET_SPM_DIR"); - int num_files; - char **files_array = get_all_files(path, path, &num_files); - if (files_array != NULL) { - // Print each file path - for (int i = 0; i < num_files; i++) { - - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - char* repo = strtok(files_array[i], "/"); - char* package = strchr(files_array[i], '\0') + 1; - printf("%s from %s\n", package, repo); - - // Free each file path string - free(files_array[i]); - } - // Free the array of file paths - free(files_array); - } else { - // If no files found, print a message - printf("No files found.\n"); - } - return 0; -} - -// Function to search for a term in installed files -char ** search(char *term, int *num_results) { - int found = 0; - const char *path = getenv("SOVIET_REPOS_DIR"); - int num_files; - char **files_array = get_all_files(path, path, &num_files); - char **searched_array = NULL; - - if (files_array != NULL) { - // Print each file path - for (int i = 0; i < num_files; i++) - { - - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - char* repo = strtok(files_array[i], "/"); - char* package = strchr(files_array[i], '\0') + 1; - - char* package_name = calloc(strlen(package) + 2, sizeof(char)); - strcpy(package_name, package); - - while(strtok(package_name, "/")) - { - char* tmp = package_name; - package_name = strchr(package_name, '\0') + 1; - if(*package_name == '\0') - { - package_name = tmp; - break; - } - } - - dbg(1, "repos is %s, package is %s, name is %s",repo, package, package_name); - - if (strstr(package_name, term) != 0) - { - // Compare the filename - printf("Found package: %s in %s \n", package_name, repo); - searched_array = realloc(searched_array, (found + 1) * sizeof(char *)); - // Stupid - char* tmp = calloc(strlen(package_name) + strlen(repo) * 2, 1); - sprintf(tmp, "%s>%s", package_name, repo); - - searched_array[found] = strdup(tmp); - free(tmp); - found++; - } - - // Free each file path string - free(files_array[i]); - } - // Free the array of file paths - free(files_array); - - // Update num_results if it's not NULL - if (num_results != NULL) - *num_results = found; - - return searched_array; - } else { - // If no files found, print a message - printf("All repositories are empty.\n"); - return NULL; - } - - if(found == 0) - { - printf("Package not found: %s\n", term); - } - return 0; -} - diff --git a/src/load.c b/src/load.c deleted file mode 100644 index b0fe0c4..0000000 --- a/src/load.c +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include -#include - -#include - -// Include necessary headers - -// class stuff -#include "libspm.h" -#include "cutils.h" - -// Additional custom header includes - -// Function to get a file from a local repository -/* -Accepts: -- const char* file_path: The local file path to save the downloaded resource. - -Returns: -- int: An integer indicating the result of the download operation. - - 0: get success. - - 1: get failure. -*/ -char* load_from_repo(const char* in, const char* in_repo, const char* file_path) -{ - // Try to find package in repos - dbg(3, "loading %s from %s", in, in_repo); - - char* path = calloc(MAX_PATH, 1); - sprintf(path, "%s/%s", getenv("SOVIET_REPOS_DIR"), in_repo); - - int count; - char **found = get_all_files(path, path, &count); - char* pkg = calloc(MAX_PATH + strlen(getenv("SOVIET_DEFAULT_FORMAT")) + 1, sizeof(char)); - if(!strstr(in, ".ecmp")) - { - sprintf(pkg, "%s.%s", in, getenv("SOVIET_DEFAULT_FORMAT")); - } - else - { - pkg = strdup(in); - } - - if (found != NULL) - { - // Print each file path - for (int i = 0; i < count; i++) - { - - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - dbg(3, "checking %s", found[i]); - char* temp = strdup(found[i]); - char* temp_path = strdup(found[i]); - - char* tok = strtok(temp, "/"); - char* repo = strdup(tok); - char* package = NULL; - while(tok != NULL ) - { - tok = strtok(NULL, "/"); - if(tok != NULL) - { - if(strstr(tok, ".ecmp")) - { - package = strdup(tok); - } - } - } - if(package == NULL) - { - dbg(3, "%s not .ecmp package, moving on", found[i]); - // Move the file to the end - char* tar = found[i]; - for (int k = i; k < count - 1; k++) - { - found[k] = found[k + 1]; - } - found[count - 1] = tar; - count--; - i--; - } - else - { - dbg(3, "Comparing %s and %s", package, pkg); - - if (strcmp(package, pkg) == 0) - { - // Compare the filename - dbg(3, "Loading package %s from %s", temp_path, in_repo); - - // Create the full PATH by combining the repository URL and the provided path - char* path = calloc(strlen(repo) + strlen(getenv("SOVIET_REPOS_DIR")) + MAX_PATH, sizeof(char)); - sprintf(path, "%s/%s/%s", getenv("SOVIET_REPOS_DIR"), in_repo, temp_path); - dbg(3, "Loading package from path: %s", path); - // Log a message about the download process - - // Attempt to load the file - if (loadFile(path, file_path) == 0) - { - // Clean up and return success - free(path); - free(found); - return repo; - } - // Clean up URL memory - free(path); - free(found); - } - - // Free each file path string - free(package); - free(repo); - free(temp); - } - } - } - return NULL; -} - -// Function to load a file from a given repo and save it to a specified path -/* -Accepts: -- const char* path: The path of the file to download. -- const char* file_path: The local file path to save the downloaded file. - -Returns: -- int: An integer indicating the result of the download operation. - - 0: Download success. - - -1: Download failure. -*/ -int loadFile(const char* path, const char* file_path) -{ - char cmd[PATH_MAX*2 + 64]; - sprintf(cmd, "cp %s %s", path, file_path); - - // Check if the download was successful - // lmao - if (system(cmd) == -1) - { - return -1; - } - // Return success - - return 0; -} diff --git a/src/locations.c b/src/locations.c deleted file mode 100755 index 4e5bcd4..0000000 --- a/src/locations.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -// Include necessary headers -#include "globals.h" -#include "libspm.h" -#include "cutils.h" - -// Function to retrieve file locations within a directory -/* -Accepts: -- char*** locations: Pointer to an array of strings to store file locations. -- const char* loc_dir: Path to the directory to search for files. - -Returns: -- long: The number of file locations retrieved. -*/ -long get_locations(char*** locations, const char* loc_dir) { - - int num_files; - *locations = get_all_files(loc_dir+1, loc_dir, &num_files); - // Log the count of retrieved locations for debugging - dbg(2, "Got %d locations", num_files); - - // Return the count of file locations - return num_files; -} diff --git a/src/make.c b/src/make.c index 13fb3d5..3fa0479 100755 --- a/src/make.c +++ b/src/make.c @@ -23,11 +23,7 @@ - -2: Failed to install the package. - -3: No install command found. */ -int make(char* package_dir, struct package* pkg) { - char* build_dir = getenv("SOVIET_BUILD_DIR"); - (void)build_dir; - char* make_dir = getenv("SOVIET_MAKE_DIR"); - +int make(struct package* pkg) { char* cmd_params; if (QUIET) { cmd_params = "&> /dev/null"; @@ -35,19 +31,13 @@ int make(char* package_dir, struct package* pkg) { cmd_params = ""; } - // TODO: this - // Thinking about putting the package caching here - // Maybe it will check if the installed version matches $VERSION - // If so, it will just copy the dir from /usr/src/$NAME-$VERSION - // Instead of executing the following: - // // Parse the files for (int i = 0; i < pkg->filesCount; i++) { int download_attempts = 3; (void)download_attempts; - int download_success = 0; - (void)download_success; + int download_success = 0; + (void)download_success; struct stat st_source = {0}; struct stat st_source_loc = {0}; @@ -66,6 +56,9 @@ int make(char* package_dir, struct package* pkg) { sprintf(location, "%s/%s", getenv("SOVIET_MAKE_DIR"), file_name); sprintf(source_location, "%s/%s-%s", getenv("SOVIET_SOURCE_DIR"), getenv("NAME"), getenv("VERSION")); sprintf(source_file_location, "%s/%s-%s/%s", getenv("SOVIET_SOURCE_DIR"), getenv("NAME"), getenv("VERSION"), file_name); + dbg(4,location); + dbg(4,source_location); + dbg(4,source_file_location); dbg(1, "Downloading %s", file_name); @@ -83,13 +76,6 @@ int make(char* package_dir, struct package* pkg) { download(file_url, fp); fclose(fp); - // Check if the checksum shall be bypassed - - if (INSECURE) { - msg(WARNING, "The Checksum is being skipped"); - goto skip_checksum; - } - // Check the hash, abort if mismatch unsigned char hash[SHA256_DIGEST_LENGTH]; char* hash_str = calloc(SHA256_DIGEST_LENGTH, 8); @@ -105,22 +91,22 @@ int make(char* package_dir, struct package* pkg) { if (buffer == NULL) { msg(FATAL, "Could not verify the file's hash"); - return -1; + return 2; } SHA256((unsigned char*) buffer, size, hash); - /* This caused and warning and functionally does nothing. Here hash is an array of unsigned char, but arrays in C are not pointers that can be NULL. This should probably be done with fread or fopen instead. Commenting out for now to silence the warning*/ + /* This caused and warning and functionally does nothing. Here hash is an array of unsigned char, but arrays in C are not pointers that can be NULL. This should probably be done with fread or fopen instead. Commenting out for now to silence the warning*/ /*if (hash == NULL) { msg(FATAL, "Could not verify the file's hash"); return -1; }*/ - dbg(1, "Hash is %s", file_sha256); for(int k = 0; k < SHA256_DIGEST_LENGTH; k++) { char* temp = calloc(8, 1); sprintf(temp, "%02x", hash[k]); strcat(hash_str, temp); + free(temp); } dbg(1, "Got %s", hash_str); @@ -130,95 +116,45 @@ int make(char* package_dir, struct package* pkg) { free(hash_str); free(buffer); - skip_checksum: - dbg(1, "Download finished"); - loadFile(location, source_file_location); + cp(location, source_file_location); } else { dbg(1, "Loading form %s", source_location); - loadFile(source_file_location, location); + cp(source_file_location, location); } - free(files); + free(files); free(location); free(source_location); free(source_file_location); } - // Download package sources - if (pkg->info.download != NULL && strlen(pkg->info.download) > 0) { - char sources_cmd[64 + strlen(make_dir) + strlen(pkg->info.download)]; - - sprintf(sources_cmd, "(cd %s && %s) %s ", make_dir, pkg->info.download, cmd_params); - dbg(2, "Downloading sources with %s", sources_cmd); - int res = system(sources_cmd); - - if (res != 0) { - msg(ERROR, "Failed to download sources for %s", pkg->name); - return -1; - } - } - // Run 'prepare' command if (pkg->info.prepare != NULL && strlen(pkg->info.prepare) > 0) { - char prepare_cmd[64 + strlen(package_dir) + strlen(pkg->info.prepare) + strlen(cmd_params)]; + char prepare_cmd[64 + strlen(getenv("SOVIET_MAKE_DIR")) + strlen(pkg->info.prepare) + strlen(cmd_params)]; - sprintf(prepare_cmd, "( cd %s && %s ) %s", package_dir, pkg->info.prepare, cmd_params); + sprintf(prepare_cmd, "( cd %s && %s ) %s", getenv("SOVIET_MAKE_DIR"), pkg->info.prepare, cmd_params); dbg(2, "Executing prepare command: %s", prepare_cmd); if (system(prepare_cmd) != 0) { msg(FATAL, "Failed to prepare %s", pkg->name); - return -2; + return 2; } dbg(1, "Prepare command executed!"); } - // Run 'make' command - if (pkg->info.make && strlen(pkg->info.make)) { - char make_cmd[64 + strlen(package_dir) + strlen(pkg->info.make) + strlen(cmd_params)]; - sprintf(make_cmd, "( cd %s && %s ) %s", package_dir, pkg->info.make, cmd_params); - - dbg(2, "Executing make command: %s", make_cmd); - if (system(make_cmd) != 0) { - return 1; - } - dbg(1, "Make command executed!"); - } - // Run 'test' command (if in testing mode) if (pkg->info.test != NULL && TESTING && strlen(pkg->info.test) > 0) { - char test_cmd[64 + strlen(package_dir) + strlen(pkg->info.test) + strlen(cmd_params)]; - sprintf(test_cmd, "( cd %s && %s ) %s", package_dir, pkg->info.test, cmd_params); + char test_cmd[64 + strlen(getenv("SOVIET_MAKE_DIR")) + strlen(pkg->info.test) + strlen(cmd_params)]; + sprintf(test_cmd, "( cd %s && %s ) %s", getenv("SOVIET_MAKE_DIR"), pkg->info.test, cmd_params); dbg(2, "Executing test command: %s", test_cmd); if (system(test_cmd) != 0) { - return 1; + return 2; } dbg(1, "Test command executed!"); } - - return 0; -} - -// Function to execute a special command for post-installation -/* -Accepts: -- const char* cmd: The special command to execute. -- const char* package_dir: Path to the package directory. - -Returns: -- int: An integer indicating the result of the special command execution. - - 0: Special command executed successfully. - - 1: An error occurred during special command execution. -*/ -int exec_special(const char* cmd, const char* package_dir) { - dbg(2, "Executing special command: %s", cmd); - - if (system(cmd) != 0) { - return 1; - } - dbg(1, "Special command executed!"); return 0; -} +} \ No newline at end of file diff --git a/src/move.c b/src/move.c index e4eb176..fcb06f3 100755 --- a/src/move.c +++ b/src/move.c @@ -39,14 +39,8 @@ void move_binaries(char** locations, long loc_size) { // Check if the destination location is empty if (!(access(dest_loc, F_OK) != 0)) { - if (OVERWRITE) - { - remove(dest_loc); - } - else - { - msg(FATAL, "%s is already here, use --overwrite?", locations[i]); - } + dbg(1, "%s is already here", locations[i]); + remove(dest_loc); } if (locations[i] == NULL) diff --git a/src/pkg.c b/src/pkg.c index 137359c..5c25c9a 100644 --- a/src/pkg.c +++ b/src/pkg.c @@ -3,161 +3,434 @@ #include "string.h" #include #include +#include #include "cutils.h" #include "libspm.h" -// Open a package from the given path and populate the package structure -/* -Accepts: -- const char* path: The path to the package file. -- struct package* pkg: A pointer to the package structure to populate. -- const char* format: The format of the package (optional). - -Description: -This function opens a package from the specified path, reads the package file's format, and populates the provided package structure with its contents. - -Returns: -- int: An integer indicating the result of opening the package. - - 0: Package opened successfully. - - 1: File does not exist or is not a valid package file. - - 1: File is not a valid package file or the format plugin isn't loaded. -*/ -int open_pkg(const char* path, struct package* pkg, const char* format) { - dbg(2, "Setting everything to NULL"); - // Set all variables to NULL - memset(pkg, 0, sizeof(struct package)); - - // Print make dependencies count - dbg(3, "make dependencies count: %d", pkg->optionalCount); - dbg(3, "path: %s", path); +// Allocate an array of packages +struct packages* create_pkgs(int reserve) +{ + struct packages* pkgs = calloc(1, sizeof(struct packages)); + pkgs->size = 1 + reserve; + pkgs->count = 0; + pkgs->buffer = (struct package*)calloc(1 + reserve, sizeof(struct package)); + return pkgs; +} + +// Merge 2 package arrays +void merge_pkgs(struct packages* destination, struct packages* source) +{ + for(int i = 0; source->count != 0; i++) + { + struct package* pkg = pop_pkg(source); + push_pkg(destination, pkg); + } + free(source->buffer); + free(source); +} + +// Free a package array +void free_pkgs(struct packages* pkgs) +{ + for(int i = 0; pkgs->count != 0; i++) + { + struct package* pkg = pop_pkg(pkgs); + free_pkg(pkg); + } + + free(pkgs->buffer); + free(pkgs); +} + +// Push a package into the array +void push_pkg(struct packages* pkgs, struct package* pkg) +{ + if (pkgs->count == pkgs->size) + { + pkgs->buffer = realloc(pkgs->buffer, sizeof(struct package)*(pkgs->count + pkgs->size)); + pkgs->size = pkgs->count + pkgs->size; + } + (pkgs->buffer[pkgs->count]) = *pkg; + pkgs->count++; +} + +// Pop the last added package from the array +struct package* pop_pkg(struct packages* pkgs) +{ + pkgs->count--; + return &(pkgs->buffer[pkgs->count]); +} +// Open a package from the given path and populate the package structure +int open_pkg(const char* path, struct package* pkg) +{ + char full_path[MAX_PATH]; + sprintf(full_path, "%s/%s", path, pkg->path); + dbg(3, "path: %s", full_path); // Check if the file exists - if (access(path, F_OK) != 0) { - msg(ERROR, "File %s does not exist\n", path); + if (access(full_path, F_OK) != 0) { + dbg(1, "File %s does not exist", full_path); return 1; } - // Check file extension - if (format == NULL) { - dbg(2, "Getting format from file extension"); - format = strrchr(path, '.') + 1; - dbg(1, "Format: %s\n", format); - } + dbg(2, "Getting format from file extension"); + char* format = strrchr(full_path, '.') + 1; + dbg(1, "Format: %s", format); char** FORMATS; int FORMAT_COUNT = splita(getenv("SOVIET_FORMATS"), ' ', &FORMATS); if (format != NULL) { // This is experimental - for (int i = 0; i < FORMAT_COUNT; i++) { - dbg(2, "format: %s = %s\n", format, FORMATS[i]); - if (strcmp(format, FORMATS[i]) == 0) { + for (int i = 0; i < FORMAT_COUNT; i++) + { + dbg(2, "format: %s = %s", format, FORMATS[i]); + if (strcmp(format, FORMATS[i]) == 0) + { dbg(2, "Opening package with %s format", FORMATS[i]); - runFormatLib(FORMATS[i], "open", path, pkg); + runFormatLib(FORMATS[i], "open", full_path, pkg); + free(FORMATS[i]); + free(FORMATS); return 0; } + free(FORMATS[i]); } + free(FORMATS); } else { - msg(ERROR, "File %s is not a valid package file", path); - return 1; + dbg(1, "File %s is not a valid package file", full_path); + return 2; } - msg(ERROR, "File %s is not a valid package file, or the format plugin isn't loaded", path); - return 1; + dbg(1, "File %s is not a valid package file, or the format plugin isn't loaded", full_path); + return 2; } -// Create a package at the given path using the specified format and package structure -/* -Accepts: -- const char* path: The path to the package file to be created. -- struct package* pkg: A pointer to the package structure containing package data. -- const char* format: The format of the package (optional). +// Create a package at the given path using the specified package structure +int create_pkg(char* in_path, struct package* pkg) +{ + char path[MAX_PATH]; + sprintf(path, "%s/%s", in_path, pkg->path); -Description: -This function creates a package file at the specified path using the provided format and package data from the package structure. + // This might seem stupid + // and it is + if(isdir(path) != 0) + { + pmkdir(path); + rmany(path); + } -Returns: -- int: An integer indicating the result of creating the package. - - 0: Package created successfully. - - -1: File is not a valid package file or the format plugin isn't loaded. -*/ -int create_pkg(const char* path, struct package* pkg, const char* format) { - msg(INFO, "Creating package %s", path); + dbg(2, "Creating package %s", path); - char** FORMATS; - int FORMAT_COUNT = splita(strdup(getenv("SOVIET_FORMATS")),' ',&FORMATS); + dbg(2, "Getting format from file extension"); + char* format = strrchr(path, '.') + 1; + dbg(1, "Format: %s", format); - // get file extension - if (format == NULL) - { - format = strrchr( path, '.' ) + 1; - } - /* This illustrates strrchr */ + char** FORMATS; + int FORMAT_COUNT = splita(getenv("SOVIET_FORMATS"),' ',&FORMATS); + if (format != NULL) { // this is experimental for (int i = 0; i < FORMAT_COUNT; i++) { - if (strcmp(format,FORMATS[i]) == 0) + if (strcmp(format, FORMATS[i]) == 0) { - dbg(2,"Opening package with %s format",FORMATS[i]); - runFormatLib(FORMATS[i],"create",path,pkg); - //free(*FORMATS); - //free(FORMATS); + dbg(2, "Opening package with %s format", FORMATS[i]); + runFormatLib(FORMATS[i], "create", path, pkg); + free(FORMATS[i]); + free(FORMATS); return 0; } + free(FORMATS[i]); } } - msg(ERROR,"File %s is not a valid package file, or the format plugin isn't loaded",path); - //free(*FORMATS); + msg(ERROR,"File %s is not a valid package file, or the format plugin isn't loaded", path); free(FORMATS); - return -1; + return 1; } -// Load a format plugin, execute a specific function, and close the plugin -/* -Accepts: -- const char* format: The format of the package. -- const char* fn: The name of the function to execute in the format plugin. -- const char* pkg_path: The path to the package file. -- struct package* pkg: A pointer to the package structure. - -Description: -This function loads a format plugin, executes a specified function within the plugin, and then closes the plugin. - -Returns: -- int: An integer indicating the result of running the format plugin. - - 0: Format plugin executed successfully. - - 1: Format plugin file does not exist. - - 1: Error loading or executing the format plugin. - - -1: Format plugin function returned an error. -*/ -int runFormatLib(const char* format, const char* fn, const char* pkg_path, struct package* pkg) { - char lib_path[MAX_PATH]; - sprintf(lib_path, "%s/%s.so", getenv("SOVIET_PLUGIN_DIR"), format); - dbg(2, "Loading %s", lib_path); - - if (access(lib_path, F_OK) != 0) { - msg(ERROR, "File %s does not exist", lib_path); - return 1; - } +// Function to free memory allocated for a package structure +int free_pkg(struct package* pkg) +{ + if (pkg->name != NULL) free(pkg->name); + if (pkg->version != NULL) free(pkg->version); + if (pkg->license != NULL) free(pkg->license); + if (pkg->type != NULL) free(pkg->type); + if (pkg->url != NULL) free(pkg->url); + if (pkg->description != NULL) free(pkg->description); + if (pkg->environment != NULL) free(pkg->environment); + if (pkg->path != NULL) free(pkg->path); - // Load a function from the shared library - void* handle = dlopen(lib_path, RTLD_LAZY); - if (!handle) { - fprintf(stderr, "%s\n", dlerror()); - return 1; + if (pkg->info.install != NULL) free(pkg->info.install); + if (pkg->info.special != NULL) free(pkg->info.special); + if (pkg->info.prepare != NULL) free(pkg->info.prepare); + if (pkg->info.test != NULL) free(pkg->info.test); + + if (pkg->locations) + { + for(int i = 0; i < pkg->locationsCount; i++) + { + free(pkg->locations[i]); + } + free(pkg->locations); } - int (*func)(const char*, struct package*) = dlsym(handle, fn); - char* error = dlerror(); - if (error != NULL) { - fprintf(stderr, "%s\n", error); - return 1; + if (pkg->dependencies) + { + for(int i = 0; i < pkg->dependenciesCount; i++) + { + free(pkg->dependencies[i]); + } + free(pkg->dependencies); + } + if (pkg->optional) + { + for(int i = 0; i < pkg->optionalCount; i++) + { + free(pkg->optional[i]); + } + free(pkg->optional); + } + if (pkg->files) + { + for(int i = 0; i < pkg->filesCount; i++) + { + free(pkg->files[i]); + } + free(pkg->files); + } + if (pkg->config) + { + for(int i = 0; i < pkg->configCount; i++) + { + free(pkg->config[i]); + } + free(pkg->config); } - if (func(pkg_path, pkg) != 0) { - return -1; + return 0; +} + +// Function to search for a package in the database +struct packages* search_pkgs(char* db_path, char* term) +{ + sqlite3* db; + int result = sqlite3_open(db_path, &db); + if(result) {msg(ERROR, "SQL error when opening SOVIET_DB");} + struct packages* pkgs = create_pkgs(256 /*absolutely random number*/); + + // Prepare the SQL query + // yes, this is a copy-paste from what we had a year ago + sqlite3_stmt* stmt; + result = sqlite3_prepare_v2(db, "SELECT Name, Path FROM Packages", -1, &stmt, NULL); + if (result != SQLITE_OK) { msg(ERROR, "SQL error when preparing to search"); } + + while ((result = sqlite3_step(stmt)) == SQLITE_ROW) + { + // TODO: This very is stupid + const unsigned char* name = sqlite3_column_text(stmt, 0); + const unsigned char* path = sqlite3_column_text(stmt, 1); + if(strstr((const char*)name, term) != 0) + { + dbg(2, "FOUND: %s at %s", name, path); + struct package pkg = {0}; + pkg.name = strdup((const char*)name); + pkg.path = strdup((const char*)path); + push_pkg(pkgs, &pkg); + } } - dlclose(handle); + result = sqlite3_finalize(stmt); + if (result != SQLITE_OK) { msg(ERROR, "SQL error when finalizing statement"); } + + sqlite3_close(db); + return pkgs; +} + +// Create the database that stores all packages in a directory +int create_pkg_db(char* db_path, struct packages* pkgs) +{ + rmany(db_path); + sqlite3* db; + int result = sqlite3_open(db_path, &db); + if(result) {msg(ERROR, "SQL error when creating SOVIET_DB"); return result;} + + result = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS Packages (Name TEXT, Path TEXT)", NULL, NULL, NULL); + if (result != SQLITE_OK) {msg(ERROR, "SQL error when creating pkg_table"); return result;} + + for(int i = 0; i < pkgs->count; i++) + { + sqlite3_stmt* stmt; + result = sqlite3_prepare_v2(db, "INSERT INTO Packages VALUES (?,?)", -1, &stmt, NULL); if (result != SQLITE_OK) { msg(ERROR, "SQL error when preparing to insert package"); return result; } + result = sqlite3_bind_text(stmt, 1, pkgs->buffer[i].name, -1, NULL); if (result != SQLITE_OK) { msg(ERROR, "SQL error when binding package name"); return result; } + result = sqlite3_bind_text(stmt, 2, pkgs->buffer[i].path, -1, NULL); if (result != SQLITE_OK) { msg(ERROR, "SQL error when binding package path"); return result; } + result = sqlite3_step(stmt); if (result != SQLITE_DONE) { msg(ERROR, "SQL error when inserting package"); return result; } + result = sqlite3_reset(stmt); if (result != SQLITE_OK) { msg(ERROR, "SQL error when resetting statement"); return result; } + result = sqlite3_finalize(stmt); if (result != SQLITE_OK) { msg(ERROR, "SQL error when finalizing statement"); return result; } + + } + + sqlite3_close(db); return 0; } + +// Get all packages from a directory +struct packages* get_pkgs(char* path) +{ + // NOTE: + // it only checks the default format + // not sure if that's a good idea + int num_files; + char **files_array = get_all_files(path, path, &num_files); + if (files_array != NULL) + { + // TODO: get rid of the nested if's + struct packages* pkgs = create_pkgs(num_files); + for (int j = 0; j < num_files; j++) + { + if(strstr(files_array[j], "/.") == NULL) + { + if(strstr(files_array[j], getenv("SOVIET_DEFAULT_FORMAT")) != NULL) + { + if(strstr(files_array[j], getenv("SOVIET_DEFAULT_FORMAT"))[strlen(getenv("SOVIET_DEFAULT_FORMAT"))] == '\0') + { + dbg(1, "file: %s", files_array[j]); + + char path[MAX_PATH]; + sprintf(path, "%s", files_array[j]); + char name[MAX_PATH]; + sprintf(name, "%s", files_array[j]); + + while(strrchr(name, '/') != NULL) + { + memmove(name, strrchr(name, '/') + 1, strlen(strrchr(name, '/') + 1) + 1); /*tbh i just added +1 untill it worked*/ + } + + name[strlen(name) - (strlen(getenv("SOVIET_DEFAULT_FORMAT")) + 1) /*+1 for the '.'*/] = '\0'; + + dbg(1, "name: %s", name); + + struct package pkg = {0}; + pkg.name = strdup(name); + pkg.path = strdup(path); + + push_pkg(pkgs, &pkg); + } + // Garbage file + } + // Not "SOVIET_DEFAULT_FORMAT" file + } + // "hidden" file + free(files_array[j]); + } + // Free the array of file paths + free(files_array); + if(pkgs->count < 1) + { + msg(ERROR, "Path %s does not contain any packages", path); + struct packages* pkgs = create_pkgs(0); + return pkgs; + } + return pkgs; + } + else + { + msg(ERROR, "Path %s empty", path); + struct packages* pkgs = create_pkgs(0); + return pkgs; + } +} + +// Function to dump a database into an array of packages +struct packages* dump_db(char* db_path) +{ + sqlite3* db; + int result = sqlite3_open(db_path, &db); + if(result) {msg(ERROR, "SQL error when opening SOVIET_DB");} + struct packages* pkgs = create_pkgs(256 /*absolutely random number*/); + + // Prepare the SQL query + // yes, this is a copy-paste from what we had a year ago + sqlite3_stmt* stmt; + result = sqlite3_prepare_v2(db, "SELECT Name, Path FROM Packages", -1, &stmt, NULL); + if (result != SQLITE_OK) { msg(ERROR, "SQL error when preparing to search"); } + + while ((result = sqlite3_step(stmt)) == SQLITE_ROW) + { + const unsigned char* name = sqlite3_column_text(stmt, 0); + const unsigned char* path = sqlite3_column_text(stmt, 1); + + struct package pkg = {0}; + + pkg.name = strdup((const char*)name); + pkg.path = strdup((const char*)path); + push_pkg(pkgs, &pkg); + } + + result = sqlite3_finalize(stmt); + if (result != SQLITE_OK) { msg(ERROR, "SQL error when finalizing statement"); } + + sqlite3_close(db); + return pkgs; +} + +// Function returns an array of packages that need updating +struct packages* update_pkg() +{ + msg(INFO, "fetching updates"); + + if(access(getenv("SOVIET_INSTALLED_DB"), F_OK) != 0) + { + msg(ERROR, "no installed DB found"); + return create_pkgs(0); + } + + struct packages* installed_packages = dump_db(getenv("SOVIET_INSTALLED_DB")); + if(installed_packages->count < 1) + { + msg(ERROR, "no installed packages"); + return create_pkgs(0); + } + + struct packages* pkgs = create_pkgs(installed_packages->count); + + for(int i = 0; i < installed_packages->count; i++) + { + struct package remote_package = {0}; + remote_package.name = strdup(installed_packages->buffer[i].name); + remote_package.path = strdup(installed_packages->buffer[i].path); + // TODO: get rid of the nested if's + if (open_pkg(getenv("SOVIET_REPOS_DIR"), &remote_package ) == 0) + { + if (open_pkg(getenv("SOVIET_SPM_DIR"), &(installed_packages->buffer[i])) == 0) + { + if(strcmp(remote_package.version, installed_packages->buffer[i].version) != 0) + { + // We don't actually know if it's older or newer + dbg(2, "package %s version %s differs from remote", installed_packages->buffer[i].name, installed_packages->buffer[i].version); + // I suppose it doens't matter which package we push + push_pkg(pkgs, &remote_package); + } + else + { + dbg(2, "package %s is up to date", installed_packages->buffer[i].name); + free_pkg(&remote_package); + } + } + else + { + // The local package does not exist, the database is corrupt/outdated + msg(ERROR, "package %s does not exist", installed_packages->buffer[i].name); + free_pkg(&remote_package); + } + } + else + { + // The package does not exist on the remote side + dbg(2, "package %s is local", installed_packages->buffer[i].name); + free_pkg(&remote_package); + } + + } + + free_pkgs(installed_packages); + return pkgs; +} \ No newline at end of file diff --git a/src/quit.c b/src/quit.c deleted file mode 100644 index 51331d5..0000000 --- a/src/quit.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -#include "cutils.h" - -// Quit the program with the given status code and display an error message if status is not 0 -/* -Accepts: -- int status: The exit status code. - -Description: -This function exits the program with the specified status code. If the status code is not 0 (indicating an error), it also displays an error message. - -Returns: -- void: This function does not return a value. -*/ -void quit(int status) { - if (status != 0) { - msg(ERROR, "Exiting with status %d", status); - exit(status); - } -} diff --git a/src/remove.c b/src/remove.c deleted file mode 100644 index f62e03a..0000000 --- a/src/remove.c +++ /dev/null @@ -1,50 +0,0 @@ -#define _XOPEN_SOURCE 500 -#include -#include -#include - -#include "libspm.h" - -// Callback function used by nftw to unlink files and directories -/* -Accepts: -- const char *fpath: The path of the file or directory being processed. -- const struct stat *sb: A pointer to a structure containing information about the file. -- int typeflag: A flag indicating the type of the file (file, directory, etc.). -- struct FTW *ftwbuf: A pointer to a structure containing state information for the traversal. - -Returns: -- int: An integer indicating the result of the operation. - - 0: The operation was successful. - - Non-zero: An error occurred during the operation. - -Description: -This function is used as a callback by the nftw function to unlink (remove) files and directories. It attempts to remove the file or directory specified by 'fpath' and returns 0 if the removal is successful. If an error occurs during the removal, it returns a non-zero value and prints an error message indicating the file or directory that caused the error. -*/ -int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) -{ - int rv = remove(fpath); - - if (rv) - perror(fpath); - - return rv; -} - -// Recursively remove a directory and its contents -/* -Accepts: -- char *path: The path of the directory to be removed. - -Returns: -- int: An integer indicating the result of the operation. - - 0: The directory and its contents were successfully removed. - - Non-zero: An error occurred during the removal. - -Description: -This function recursively removes a directory and its contents. It utilizes the nftw function to traverse the directory and its subdirectories, invoking the 'unlink_cb' callback function to unlink and remove files and directories. It returns 0 if the removal is successful and a non-zero value if an error occurs during the operation. -*/ -int rmrf(char *path) -{ - return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); -} diff --git a/src/get.c b/src/repo.c similarity index 75% rename from src/get.c rename to src/repo.c index bf8ebe6..79ee30c 100755 --- a/src/get.c +++ b/src/repo.c @@ -1,7 +1,7 @@ -#include #include #include #include +#include #include #include #include @@ -11,79 +11,61 @@ #include "globals.h" #include "cutils.h" -// Function to retrieve a package from a data repository -/* -Accepts: -- struct package* i_pkg: A pointer to a package structure with package details. -- const char* out_path: The local path to save the downloaded package. - -Returns: -- char*: A pointer to the package format or NULL if there's an error. -*/ -char* get(struct package* i_pkg, const char* repo, const char* out_path) -{ - // Check if the package name is specified - if (i_pkg->name == NULL) - { - msg(ERROR, "Package name not specified!"); - return NULL; - } - - return load_from_repo(i_pkg->name, repo, out_path); -} - -int get_repos(char** list) +// Get currently present repos +char** get_repos(int* count) { + char** list = calloc(512, sizeof(char*)); dbg(3, "checking for repos"); DIR *d; struct dirent *dir; d = opendir(getenv("SOVIET_REPOS_DIR")); - int count = 0; - list[count] = calloc(strlen("local") + 1, 1); - sprintf(list[count], "local"); - count++; + *count = 0; + list[*count] = calloc(strlen("local") + 1, 1); + sprintf(list[*count], "local"); + (*count)++; if (d) { while ((dir = readdir(d)) != NULL) { - if (count > 512) + if (*count > 512) { printf("Error : too many elements in list , reallocating\n"); - list = realloc(list,(count+512) * sizeof(char*)); + list = realloc(list,(*count+512) * sizeof(char*)); } if (dir->d_type != DT_DIR || dir->d_name[0] == '.') continue; - list[count] = calloc(strlen(dir->d_name) + 1, sizeof(char)); - strcpy(list[count], dir->d_name); - count++; + list[*count] = calloc(strlen(dir->d_name) + 1, sizeof(char)); + strcpy(list[*count], dir->d_name); + (*count)++; } } - for (int i = 0; i < count - 1; i++) + for (int i = 0; i < *count - 1; i++) { if (strcmp(list[i], ".") == 0 || strcmp(list[i], "..") == 0) { // Move the . string to the end char* temp = list[i]; dbg(3, "Moving: %s", temp); - for (int k = i; k < count - 1; k++) + for (int k = i; k < *count - 1; k++) { list[k] = list[k + 1]; } - list[count - 1] = temp; + list[*count - 1] = temp; i--; - count--; + (*count)--; } } closedir(d); dbg(3, "done checking for repos"); - return count; + return list; } // Function to synchronize the local repository with a remote repository -int repo_sync() { +int repo_sync() +{ char* repo_dir = getenv("SOVIET_REPOS_DIR"); char* repo_url = getenv("SOVIET_DEFAULT_REPO_URL"); char* submodule_name = getenv("SOVIET_DEFAULT_REPO"); @@ -119,7 +101,8 @@ int repo_sync() { // Initialize a new Git repository if (git_repository_init(&repo_handle, repo_dir, false) != 0) { - msg(FATAL, "Failed to initialize git repository in %s.", repo_dir); + const git_error* error = giterr_last(); + msg(FATAL, "Failed to initialize git repository in %s - %s", repo_dir, error->message); } } @@ -129,10 +112,14 @@ int repo_sync() { if (add_repo(submodule_name, repo_url) != 0) {msg(ERROR, "Failed to create the default repository");} } - // TODO: add a way to get all submodules and update them - // But maybe a single system call isn't too bad... + // TODO: get all submodules and update them without the system call // Update submodules chdir(repo_dir); + if(system("git submodule foreach --recursive git reset --hard") != 0) + { + printf("Failed to update submodules in %s\n", repo_dir); + return 3; + } if (system("git submodule update --depth 1 --remote --init --recursive") != 0) { printf("Failed to update submodules in %s\n", repo_dir); @@ -140,9 +127,11 @@ int repo_sync() { } git_repository_free(repo_handle); + return 0; } +// Add a new repository from a git repo int add_repo(char* name, char* url) { const char* repo_dir = getenv("SOVIET_REPOS_DIR"); @@ -150,8 +139,17 @@ int add_repo(char* name, char* url) // Set clone options unsigned int* status = NULL; - git_submodule_update_options opts = GIT_CLONE_OPTIONS_INIT; - git_fetch_options fopts = GIT_FETCH_OPTIONS_INIT; + git_submodule_update_options opts = {0}; + if(git_submodule_update_options_init(&opts, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)!= 0) + { + msg(FATAL, "Failed to initialize git submodule options"); + } + git_fetch_options fopts = {0}; + if(git_fetch_options_init(&fopts, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION)!= 0) + { + msg(FATAL, "Failed to initialize git fetch options"); + } + opts.fetch_opts = fopts; opts.fetch_opts.depth = 1; @@ -191,9 +189,10 @@ int add_repo(char* name, char* url) msg(ERROR, "Failed to finalize submodule %s - %s", name, error->message); return -1; } - git_submodule_free(submodule_handle); git_repository_free(temp_handle); + git_repository_free(repo_handle); + return 0; } diff --git a/src/uninstall.c b/src/uninstall.c index a2b7dff..ad333e3 100755 --- a/src/uninstall.c +++ b/src/uninstall.c @@ -9,9 +9,6 @@ #include "libspm.h" #include "cutils.h" -// remove a file or link or directory -int rmany(char* path); - // Function to uninstall packages /* Accepts: @@ -27,90 +24,42 @@ This function is used to uninstall packages. It relies on location data, which c Please avoid making changes to this code unless there's a critical bug or an important missing feature. */ -int uninstall(char* name) +int uninstall(struct package* pkg) { - // Get the SPM directory from the environment variables - char* SPM_DIR = getenv("SOVIET_SPM_DIR"); - dbg(3, "SOVIET_SPM_DIR = %s", SPM_DIR); - char* ROOT = getenv("SOVIET_ROOT"); - - char** REPOS = calloc(512,sizeof(char*)); - int REPO_COUNT = get_repos(REPOS); - char* dataSpmPath = calloc(MAX_PATH, sizeof(char)); + char dataSpmPath[MAX_PATH]; + sprintf(dataSpmPath, "%s/%s", getenv("SOVIET_SPM_DIR"), pkg->path); - for (int j = 0; j < REPO_COUNT; j++) + // Check if the SPM file exists + if (check(pkg) == 0) { - // Generate the path to the package's SPM file - char tmpSpmPath[MAX_PATH]; - sprintf(tmpSpmPath, "%s/%s/%s.%s", (char*)getenv("SOVIET_SPM_DIR"),REPOS[j], name, getenv("SOVIET_DEFAULT_FORMAT")); - - // Verify if the package is installed - msg(INFO, "Verifying if the package is installed at %s", tmpSpmPath); - - // Check if the SPM file exists - if (access(tmpSpmPath, F_OK) == 0) { - sprintf(dataSpmPath, "%s/%s/%s.%s", getenv("SOVIET_SPM_DIR"),REPOS[j], name, getenv("SOVIET_DEFAULT_FORMAT")); - // Create a struct to store package information - struct package r_pkg; - - // Open the package's SPM file and populate the r_pkg struct - open_pkg(dataSpmPath, &r_pkg, NULL); - - dbg(3, "Found %d locations", r_pkg.locationsCount); - // Remove all the files in the data["locations"] - char loc_path[MAX_PATH]; - for (int i = 0; i < r_pkg.locationsCount; i++) { - - sprintf(loc_path, "%s%s", ROOT, r_pkg.locations[i]); - - //dbg(3, "Removing %s", loc_path); - if (rmany(loc_path) != 0) { - msg(ERROR,"Failed to remove %s",loc_path); - perror("remove"); - } + // Create a struct to store package information + struct package r_pkg = {0}; + r_pkg.path = strdup(pkg->path); + + // Open the package's SPM file and populate the r_pkg struct + open_pkg(getenv("SOVIET_SPM_DIR"), &r_pkg); + + dbg(3, "Found %d locations", r_pkg.locationsCount); + // Remove all the files in the data["locations"] + char loc_path[MAX_PATH]; + for (int i = 0; i < r_pkg.locationsCount; i++) + { + sprintf(loc_path, "%s%s", getenv("SOVIET_ROOT"), r_pkg.locations[i]); + + dbg(3, "Removing %s", loc_path); + if (rmany(loc_path) != 0) { + msg(ERROR,"Failed to remove %s",loc_path); + perror("remove"); } - // Remove the SPM file from DATA_DIR - remove(dataSpmPath); - return 0; } + // Remove the SPM file from DATA_DIR + remove(dataSpmPath); + free_pkg(&r_pkg); + return 0; } + msg(ERROR, "package not installed"); return -1; } -int rmany(char* path) { - // check if its a symlink - struct stat s; - - if (lstat(path, &s) == 0) { - if (S_ISLNK(s.st_mode)) { - // remove the symlink - if (unlink(path) == 0) { - return 0; - } else { - return -1; - } - } - // check if its a directory - if (S_ISDIR(s.st_mode)) { - // remove the directory - if (rmdir(path) == 0) { - return 0; - } else { - msg(ERROR, "Error removing directory %s (Probably not empty)", path); - return -1; - } - } - // check if its a file - if (S_ISREG(s.st_mode)) { - // remove the file - if (remove(path) == 0) { - return 0; - } else { - return -1; - } - } - } - return -1; -} \ No newline at end of file diff --git a/src/update.c b/src/update.c deleted file mode 100644 index 1b7ea24..0000000 --- a/src/update.c +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include -#include -#include - -// Include necessary headers -#include "libspm.h" -#include "cutils.h" - -//should probably add there to the header when we are done - -int update() -{ - msg(INFO, "fetching updates"); - - int new_version_found = 0; - - const char *path = getenv("SOVIET_SPM_DIR"); - dbg(2, "path is %s", path); - const char *repo_path = getenv("SOVIET_REPOS_DIR"); - dbg(2, "repo path is %s", repo_path); - int num_files; - char **files_array = get_all_files(path, path, &num_files); - - if (files_array == NULL) { - msg(WARNING, "no packages installed"); - return 0; - } - // Print each file path - for (int i = 0; i < num_files; i++) - { - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - char* local_repo = strtok(files_array[i], "/"); - //dbg(2, "local repo is %s", local_repo); - char* local_package_name = strchr(files_array[i], '\0') + 1; - //dbg(2, "local package name is %s", local_package_name); - - // Allocate the packages to be compared - struct package* local = calloc(1, sizeof(struct package)); - struct package* remote = calloc(1, sizeof(struct package)); - - char* local_path = calloc(MAX_PATH, sizeof(char)); - char* remote_path = calloc(MAX_PATH, sizeof(char)); - - sprintf(local_path, "%s/%s/%s", path, local_repo, local_package_name); - //dbg(2, "local path is %s", local_path); - - int num_searched_files; - char **searched_files_array = get_all_files(repo_path, repo_path, &num_searched_files); - - if (searched_files_array != NULL) - { - // Print each file path - for (int j = 0; j < num_searched_files; j++) - { - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - char* remote_repo = strtok(searched_files_array[j], "/"); - //dbg(2, "remote repo is %s", remote_repo); - char* remote_package = strchr(searched_files_array[j], '\0') + 1; - //dbg(2, "remote package is %s", remote_package); - char* remote_package_name = calloc(strlen(remote_package) + 2, sizeof(char)); - strcpy(remote_package_name, remote_package); - //dbg(2, "remote package name is %s", remote_package_name); - - while(strtok(remote_package_name, "/")) - { - char* tmp = remote_package_name; - remote_package_name = strchr(remote_package_name, '\0') + 1; - if(strcmp(remote_package_name, "") == 0) - { - remote_package_name = tmp; - break; - } - } - - //printf("%s, %s \n", remote_package_name, local_package_name); - - if (strcmp(remote_repo, local_repo) == 0) - { - if (strcmp(remote_package_name, local_package_name) == 0) - { - // Compare the filename - sprintf(remote_path, "%s/%s/%s", repo_path, remote_repo, remote_package); - dbg(2, "remote path is %s", remote_path); - - open_pkg(local_path, local, "ecmp"); - open_pkg(remote_path, remote, "ecmp"); - - // Compare the versions - if(strcmp(local->version, remote->version) != 0) - { - msg(INFO, "package %s is at version %s, available version is %s", local->name, local->version, remote->version); - new_version_found = 1; - } - - free(local); - free(remote); - } - } - // Free each file path string - free(searched_files_array[j]); - } - // Free each file path string - free(files_array[i]); - } - // Free the array of file paths - free(searched_files_array); - } - // Free the array of file paths - free(files_array); - - - if(new_version_found != 0) - { - msg(WARNING, "new version found for one or more packages, use --upgrade to upgrade"); - } - else - { - msg(WARNING, "all packages are up to date"); - } - - return 0; -} - -int upgrade() -{ - msg(INFO, "upgrading"); - int new_version_installed = 0; - - const char *path = getenv("SOVIET_SPM_DIR"); - const char *repo_path = getenv("SOVIET_REPOS_DIR"); - int num_files; - char **files_array = get_all_files(path, path, &num_files); - - if (files_array != NULL) - { - // Print each file path - for (int i = 0; i < num_files; i++) - { - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - char* local_repo = strtok(files_array[i], "/"); - char* local_package_name = strchr(files_array[i], '\0') + 1; - - // Allocate the packages to be compared - struct package* local = calloc(1, sizeof(struct package)); - struct package* remote = calloc(1, sizeof(struct package)); - - char* local_path = calloc(MAX_PATH, sizeof(char)); - char* remote_path = calloc(MAX_PATH, sizeof(char)); - - sprintf(local_path, "%s/%s/%s", path, local_repo, local_package_name); - - int num_searched_files; - char **searched_files_array = get_all_files(repo_path, repo_path, &num_searched_files); - - if (searched_files_array != NULL) - { - // Print each file path - for (int j = 0; j < num_searched_files; j++) - { - // This will break if the files are not separated into repos - // But it doesnt cause a crash, just a visual bug - // I think - char* remote_repo = strtok(searched_files_array[j], "/"); - char* remote_package = strchr(searched_files_array[j], '\0') + 1; - char* remote_package_name = calloc(strlen(remote_package) + 2, sizeof(char)); - strcpy(remote_package_name, remote_package); - - while(strtok(remote_package_name, "/")) - { - char* tmp = remote_package_name; - remote_package_name = strchr(remote_package_name, '\0') + 1; - if(strcmp(remote_package_name, "") == 0) - { - remote_package_name = tmp; - break; - } - } - - //printf("%s, %s \n", remote_package_name, local_package_name); - - if (strcmp(remote_repo, local_repo) == 0) - { - if (strcmp(remote_package_name, local_package_name) == 0) - { - // Compare the filename - sprintf(remote_path, "%s/%s/%s", repo_path, remote_repo, remote_package); - - open_pkg(local_path, local, "ecmp"); - open_pkg(remote_path, remote, "ecmp"); - - // Compare the versions - if(strcmp(local->version, remote->version) != 0) - { - msg(INFO, "package %s is at version %s, available version is %s", local->name, local->version, remote->version); - msg(INFO, "upgrading %s from %s to %s", local->name, local->version, remote->version); - uninstall(local->name); - - f_install_package_source(remote_path, 0, local_repo); - new_version_installed = 1; - } - - free(local); - free(remote); - } - } - // Free each file path string - free(searched_files_array[j]); - } - // Free each file path string - free(files_array[i]); - } - // Free the array of file paths - free(searched_files_array); - } - // Free the array of file paths - free(files_array); - } - else - { - // If no files found, print a message - printf("No files found.\n"); - } - - if(new_version_installed == 0) - { - msg(WARNING, "all packages are up to date"); - } - - return 0; -} diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..cb2d7ef --- /dev/null +++ b/src/util.c @@ -0,0 +1,401 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "math.h" +#include "libspm.h" +#include "cutils.h" +#include "globals.h" + +// Callback function used by nftw to unlink files and directories +int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) +{ + (void)sb; + (void)typeflag; + (void)ftwbuf; + + int rv = remove(fpath); + + if (rv) + perror(fpath); + + return rv; +} + +// Recursively remove a directory and its contents +int rmrf(char *path) +{ + return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); +} + +// remove a file or link or directory +int rmany(char* path) +{ + // check if its a symlink + struct stat s; + + if (lstat(path, &s) == 0) { + if (S_ISLNK(s.st_mode)) { + // remove the symlink + if (unlink(path) == 0) { + return 0; + } else { + return -1; + } + } + // check if its a directory + if (S_ISDIR(s.st_mode)) { + // remove the directory + if (rmrf(path) == 0) { + return 0; + } else { + msg(ERROR, "Error removing directory %s", path); + return -1; + } + } + // check if its a file + if (S_ISREG(s.st_mode)) { + // remove the file + if (remove(path) == 0) { + return 0; + } else { + return -1; + } + } + } + return -1; +} + +// Quit the program with the given status code and display an error message if status is not 0 +void quit(int status) +{ + if (status != 0) { + msg(ERROR, "Exiting with status %d", status); + exit(status); + } +} + +// Function to recursively retrieve all files in a directory and its subdirectories +char **get_all_files(const char* root, char *path, int *num_files) +{ + DIR *dir; + struct dirent *entry; + struct stat stat_buf; + char* origin = strdup(path); + // Open the directory + dir = opendir(path); + if (dir == NULL) { + // Print an error message if directory couldn't be opened + fprintf(stderr, "Error opening directory %s: %s\n", path, strerror(errno)); + free(origin); + return NULL; + } + + // Initialize variables + char **files_array = NULL; + int file_count = 0; + + // Loop through directory entries + while ((entry = readdir(dir)) != NULL) { + // Skip '.' and '..' entries + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + // Construct full path of the current entry + char full_path[MAX_PATH]; + snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); + + // Get information about the current entry + if (stat(full_path, &stat_buf) == 0) { + // If it's a directory, recursively call get_all_files + if (S_ISDIR(stat_buf.st_mode)) { + struct stat dir_stat_buf; + if (lstat(full_path, &dir_stat_buf) == 0) { + // Check if a directory is a symlink (this can probably be optimized out) + if (!S_ISLNK(dir_stat_buf.st_mode)) { + // If it isn't - treat it as a directory + int sub_files_count; + char **sub_files = get_all_files(root, full_path, &sub_files_count); + if (sub_files != NULL) { + // Resize files_array and copy contents of sub_files into it + files_array = realloc(files_array, (file_count + sub_files_count) * sizeof(char *)); + for (int i = 0; i < sub_files_count; i++) { + files_array[file_count++] = sub_files[i]; + } + free(sub_files); + } + } + else { + // If it is - treat it as a file + files_array = realloc(files_array, (file_count + 1) * sizeof(char *)); + files_array[file_count] = strdup(full_path + strlen(root) + 1); + file_count++; + } + } + } else if (S_ISREG(stat_buf.st_mode)) { + // If it's a regular file, add it to files_array + files_array = realloc(files_array, (file_count + 1) * sizeof(char *)); + files_array[file_count] = strdup(full_path + strlen(root) + 1); + file_count++; + } + } + } + // Close the directory + closedir(dir); + + // Update num_files if it's not NULL + if (num_files != NULL) + *num_files = file_count; + + // Return the array of file paths + free(origin); + + return files_array; +} + +// Load a format plugin, execute a specific function, and close the plugin +int runFormatLib(const char* format, const char* fn, const char* pkg_path, struct package* pkg) +{ + char lib_path[MAX_PATH]; + sprintf(lib_path, "%s/%s.so", getenv("SOVIET_PLUGIN_DIR"), format); + dbg(2, "Loading %s", lib_path); + + if (access(lib_path, F_OK) != 0) { + msg(ERROR, "File %s does not exist", lib_path); + return 1; + } + + // Load a function from the shared library + void* handle = dlopen(lib_path, RTLD_LAZY); + if (!handle) { + fprintf(stderr, "%s\n", dlerror()); + return 1; + } + int (*func)(const char*, struct package*) = dlsym(handle, fn); + char* error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + return 1; + } + if (func(pkg_path, pkg) != 0) { + return -1; + } + + dlclose(handle); + return 0; +} + +// A function to retrieve the version number of the libspm library. +float version() +{ + return LIBSPM_VERSION; +} + +// 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; + size_t i, start_i; + + if (start == NULL) + { + return 0; + } + + 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); + char* dup_in = calloc(start_i + 1, 1); + if(start_i != 0) + { + snprintf(dup_in, start_i + 1, "%s", *in); + } + var[--i] = '\0'; + + dbg(2, "Found variable: %s", var); + + char* full_var = getenv(var); + + if(full_var == NULL) + { + return 0; + } + + dbg(2, "Substituting for: %s", full_var); + + char* full_in = calloc(strlen(*in) + strlen(full_var) + strlen(end) + 1, 1); + + sprintf(full_in, "%s%s%s", dup_in, full_var, end); + + free(*in); + free(dup_in); + free(var); + *in = full_in; + + dbg(2, "Result: %s", *in); + + return parse_env(in); +} + +// Download a file from url into FILE +int download(char* url, FILE* fp) { + CURL *curl = curl_easy_init(); + if(curl) { + CURLcode res; + (void) res; + curl_easy_setopt(curl, CURLOPT_USERAGENT, "CCCP/1.0 (https://www.sovietlinux.org/)(rip i guess)"); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } + return 0; +} + +// Copy a file +int cp(char* from, char* to) +{ + struct stat st; + stat(from, &st); + int size = st.st_size; + int permissions = st.st_mode; + int owner = st.st_uid; + int group = st.st_gid; + + char* buffer = malloc(size); + + FILE *old_ptr; + FILE *new_ptr; + + old_ptr = fopen(from,"r"); + if (old_ptr == NULL) { + msg(ERROR,"Error opening file %s",from); + return -1; + } + fread(buffer, sizeof(char), size, old_ptr); + fclose(old_ptr); + + new_ptr = fopen(to,"w"); + if (new_ptr == NULL) { + free(buffer); + msg(ERROR,"Error opening file %s",to); + return -2; + } + fwrite(buffer, sizeof(char), size, new_ptr); + int result = fclose(new_ptr); + + if (result != 0) { + free(buffer); + msg(ERROR,"Error writing to file %s",to); + return -3; + } + + free(buffer); + + if (chown(to, owner, group) != 0) { + msg(ERROR,"Error changing owner of %s",to); + return -4; + } + if (chmod(to, permissions) != 0) { + msg(ERROR,"Error changing permissions of %s",to); + return -5; + } + + return 0; +} + +// Ask a yes/no queston +int get_input(char* prompt, int def) +{ + char* str = calloc(2, sizeof(char)); + char def_char; + + if(def == 0) + { + def_char = 'N'; + printf("%s (y/N)\n", prompt); + } + else + { + def_char = 'Y'; + printf("%s (Y/n)\n", prompt); + } + + + if(AUTO) + { + free(str); + return def; + } + else + { + fgets(str, 2, stdin); + if ( strchr(str, '\n') == NULL ) + { + while ((getchar()) != '\n'); + } + + int i = 0; + + while (str[i] != '\n' && str[i] != '\0') + { + i++; + } + + if (str[i] == '\n') + { + str[i] = '\0'; + } + } + if(str[0] == '\0') + { + str[0] = def_char; + str[1] = '\0'; + } + if(str[0] == 'Y' || str[0] == 'y') + { + free(str); + return 1; + } + free(str); + return 0; +} \ No newline at end of file diff --git a/src/version.c b/src/version.c deleted file mode 100644 index 9cded6f..0000000 --- a/src/version.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "libspm.h" - -// A function to retrieve the version number of the libspm library. -float version() -{ - return LIBSPM_VERSION; -} diff --git a/test/package.c b/test/package.c deleted file mode 100644 index 10198f3..0000000 --- a/test/package.c +++ /dev/null @@ -1,36 +0,0 @@ -// this file will be used by the our to check a package's validity. -// it replaces in this usage the test.c file, now only used for libspm testing. - -#include "test.h" - - -#define STATIC - -char WORKING_DIR[2048]; - -int main(int argc, char const *argv[]) -{ - - - // check for arguments - if (argc < 2) - { - printf("No arguments provided\n"); - return 1; - } - - // set debug level - setenv("SOVIET_DEBUG","3",1); - - char* spm_path = strdup(argv[1]); - - // check if file is a valid package - msg(INFO,"Checking package validity..."); - test_ecmp(spm_path); - msg(INFO,"Package is valid"); - msg(INFO,"Installing package..."); - test_pm(spm_path); - msg(INFO,"Package installed successfully"); - - return 0; -} \ No newline at end of file diff --git a/test/spm.c b/test/spm.c index 359e087..47c3c65 100644 --- a/test/spm.c +++ b/test/spm.c @@ -1,91 +1,48 @@ #include "test.h" +#include "../include/libspm.h" #include -char WORKING_DIR[2048]; - -int main(int argc, char const *argv[]) +int main() { msg(INFO,"Started LibSPM test suite..."); - if (argc < 2) - { - printf("No arguments provided\n"); - return 1; - } /* START LIBSPM CONFIG */ setenv("SOVIET_DEBUG","3",1); DEBUG = 3; QUIET = false; - OVERWRITE = true; DEBUG_UNIT = NULL; - // we want to chnage that later - // TODO: Add hash to test package - INSECURE = true; /* END LIBSPM CONFIG */ - char cwd[2048]; - getcwd(cwd, 2048); - sprintf(WORKING_DIR,"%s/test/assets",cwd); - - char TEST_SPM_PATH[2048]; - sprintf(TEST_SPM_PATH,"%s/vim.ecmp",WORKING_DIR); - - - - if (argc < 2 || strcmp(argv[1], "help") == 0) { - printf("Usage: %s [ecmp|all|make|install|uninstall|move|help|split|config|get]\n", argv[0]); - return 0; - } - // Check for root privileges for all other commands if (geteuid() != 0) { printf("You must have root privileges to run this command.\n"); return 1; } - if (strcmp(argv[1], "all") == 0) { - test_move(); - test_get(); - test_split(); - test_config(); - - test_ecmp(TEST_SPM_PATH); - test_make(TEST_SPM_PATH); - test_pm(TEST_SPM_PATH); + setenv("SOVIET_TEST_DIR", "/tmp/cccp-test", 1); + rmany(getenv("SOVIET_TEST_DIR")); + pmkdir(getenv("SOVIET_TEST_DIR")); - int leaks = check_leaks(); - if (leaks > 0) { - msg(ERROR, "Leaks: %d",leaks); - } - - } else if (strcmp(argv[1], "ecmp") == 0) { - test_ecmp(TEST_SPM_PATH); - } else if (strcmp(argv[1], "make") == 0) { - test_make(TEST_SPM_PATH); - printf("Leaks: %d\n", check_leaks()); - } else if (strcmp(argv[1],"install") == 0 || - strcmp(argv[1],"pm") == 0) { - test_pm(TEST_SPM_PATH); - printf("Leaks: %d\n", check_leaks()); - return 0; - } else if (strcmp(argv[1], "move") == 0) { - test_move(); - } else if (strcmp(argv[1], "split") == 0) { - test_split(); - } else if (strcmp(argv[1], "config") == 0) { - test_config(); - } else if (strcmp(argv[1], "get") == 0) { - test_get(); - } else { - printf("Invalid argument\n"); - return 1; - } + test_check(); + test_clean(); + test_config(); + test_install(); + test_make(); + test_move(); + test_pkg(); + test_repo(); + test_uninstall(); int leaks = check_leaks(); - if (leaks > 0) { + if (leaks > 0) + { msg(WARNING,"Leaks: %d",leaks); } + else + { + msg(INFO, "No leaks detected ;3"); + } msg(INFO,"Done testing LibSPM."); return 0; -} +} \ No newline at end of file diff --git a/test/test.c b/test/test.c index 36d129f..1fd1c45 100644 --- a/test/test.c +++ b/test/test.c @@ -1,330 +1,657 @@ #include "test.h" #include "../include/libspm.h" +#include -char* assemble(char** list,int count); - -extern int open_ecmp(char* path,struct package* pkg); -extern int create_ecmp(char* path,struct package* pkg); - - -void test_pm(char* spm_path) { - - msg(INFO,"Testing 'install_package_source()' and 'uninstall()'.."); - - // install tests - char temp_dir_template[] = "/tmp/test_dir_XXXXXX"; - char* test_dir = mkdtemp(temp_dir_template); - setenv("SOVIET_ROOT",test_dir,1); - char test_spm_dir[2048]; - sprintf(test_spm_dir,"%s/spm/",test_dir); - setenv("SOVIET_SPM_DIR",test_spm_dir,1); - - init() ; +void test_check() +{ + // Necessary prepwork + { + setenv("SOVIET_SPM_DIR", "/tmp/cccp-test", 1); + setenv("SOVIET_FORMATS", "ecmp", 1); + setenv("SOVIET_PLUGIN_DIR", "/var/cccp/plugins", 1); + + // I'm heavily abusing the fact that there is no check on the validity of the package + FILE *ptr; + ptr = fopen("/tmp/cccp-test/test.ecmp","w"); + fprintf(ptr, "[locations]\n"); + fprintf(ptr, "/tmp/cccp-test/test.ecmp\n"); + fclose(ptr); + } - assert(install_package_source(spm_path,0) == 0); - assert(uninstall("vim") == 0); + struct package pkg = {0}; + pkg.path = strdup("test.ecmp"); + int result = check(&pkg); + free_pkg(&pkg); - unsetenv("SOVIET_ROOT"); - unsetenv("SOVIET_ROOT"); + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); - return; + // Cleanup + { + unsetenv("SOVIET_SPM_DIR"); + unsetenv("SOVIET_FORMATS"); + unsetenv("SOVIET_PLUGIN_DIR"); + rmany("/tmp/cccp-test/test.ecmp"); + } } +void test_clean() +{ + // Necessary prepwork + { + char TEST_BUILD_DIR[MAX_PATH]; + char TEST_MAKE_DIR[MAX_PATH]; + + sprintf(TEST_BUILD_DIR, "%s/%s", getenv("SOVIET_TEST_DIR"), "TEST_BUILD_DIR"); + sprintf(TEST_MAKE_DIR, "%s/%s", getenv("SOVIET_TEST_DIR"), "TEST_MAKE_DIR"); + + setenv("SOVIET_BUILD_DIR", TEST_BUILD_DIR, 1); + setenv("SOVIET_MAKE_DIR", TEST_MAKE_DIR, 1); + pmkdir(getenv("SOVIET_BUILD_DIR")); + pmkdir(getenv("SOVIET_MAKE_DIR")); + } + int result = clean(); -void test_move() { - - msg(INFO,"Testing 'move_binaries()'.."); - - char temp_dir_template[] = "/tmp/test_dir_XXXXXX"; - char* test_dir = mkdtemp(temp_dir_template); - char build_dir[2048]; - sprintf(build_dir,"%s/build",test_dir); - - #define l_d_count 5 - #define l_f_count 12 - #define l_l_count 3 - char* l_dirs[l_d_count] = {"b","b/d","s","s/j","s/j/k"}; - char* l_files[l_f_count] = {"w","b/d/e","a","d","b/y","b/c","b/f","s/j/k/z","s/j/k/x","s/j/k/c","s/j/k/v","s/j/k/b"}; - char* l_links[l_l_count][2] = {{"b/d/e","b/e"},{"s/j/k/z","s/z"},{"s/j/k/x","s/x"}}; - - setenv("SOVIET_ROOT",test_dir,1); - setenv("SOVIET_BUILD_DIR",build_dir,1); - init(); + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); - dbg(2,"creating test dirs"); - //make all dirs - for (int i = 0; i < l_d_count; i++) + // Cleanup { - dbg(3,"Creating %s\n",l_dirs[i]); - char* dir = malloc(256); - sprintf(dir,"%s/%s",build_dir,l_dirs[i]); - mkdir(dir,0777); - free(dir); + rmany(getenv("SOVIET_BUILD_DIR")); + rmany(getenv("SOVIET_MAKE_DIR")); + unsetenv("SOVIET_BUILD_DIR"); + unsetenv("SOVIET_MAKE_DIR"); } - 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]); - FILE* f = fopen(path,"w"); - fclose(f); - free(path); - } - dbg(2,"Creating test links\n"); - // make all links - for (int i = 0; i < l_l_count; i++) +} + +void test_config() +{ + // Necessary prepwork { - dbg(3,"Creating %s -> %s\n",l_links[i][1],l_links[i][0]); - char* old_path = malloc(256); - sprintf(old_path,"%s/%s",build_dir,l_links[i][0]); - char* link_path = malloc(256); - sprintf(link_path,"%s/%s",build_dir,l_links[i][1]); - symlink(old_path,link_path); - free(old_path); - free(link_path); - } + setenv("SOVIET_TEST_ENV", "TEST", 1); - // get all the files with get_locatins - char** end_locations; - int end_count = get_locations(&end_locations,build_dir); + FILE *ptr; + ptr = fopen("/tmp/cccp-test/test.conf","w"); + fprintf(ptr, "SOVIET_TEST_VAR=$SOVIET_TEST_ENV/TEST"); + fclose(ptr); + } - assert(end_count == l_f_count + l_l_count); + int result = readConfig("/tmp/cccp-test/test.conf", 1); - move_binaries(end_locations,end_count); - // Check if the move was successful - int EXIT = 0; - for (int i = 0; i < l_f_count; i++) + if((result != 0) || (strcmp(getenv("SOVIET_TEST_VAR"), "TEST/TEST") != 0)) { - char* old_path = malloc(256); - sprintf(old_path,"%s/%s",build_dir,l_files[i]); - char* new_path = malloc(256); - sprintf(new_path,"%s/%s",test_dir,l_files[i]); - - assert(access(old_path, F_OK) == -1 && access(new_path, F_OK) == 0); - - free(old_path); - free(new_path); + msg(ERROR, "EXPECTED: 'TEST/TEST'"); + msg(ERROR, "GOT: '%s'", getenv("SOVIET_TEST_VAR")); + msg(FATAL, "FAILED"); } - // check if the links were moved - for (int i = 0; i < l_l_count; i++) + else msg(INFO, "PASSED"); + + // Cleanup { - char* old_path = malloc(256); - sprintf(old_path,"%s/%s",build_dir,l_links[i][0]); - char* new_path = malloc(256); - sprintf(new_path,"%s/%s",test_dir,l_links[i][1]); - - // check using stat - struct stat st; - assert(stat(new_path,&st) == 0 && stat(old_path,&st) != 0); - - free(old_path); - free(new_path); + unsetenv("SOVIET_TEST_ENV"); + unsetenv("SOVIET_TEST_VAR"); + rmany("/tmp/cccp-test/test.conf"); } - - - free(*end_locations); - free(end_locations); - - unsetenv("SOVIET_ROOT_DIR"); - unsetenv("SOVIET_BUILD_DIR"); - } -void test_make(char* spm_path) { - - // Set environment variables for building - setenv("BUILD_ROOT", getenv("SOVIET_BUILD_DIR"), 1); +void test_install() +{ + int result = 0; - msg(INFO,"Testing 'make()'.."); + // Necessary prepwork + { + setenv("SOVIET_SPM_DIR", "/tmp/cccp-test/spm_dir", 1); + setenv("SOVIET_SOURCE_DIR", "/tmp/cccp-test/src_dir", 1); + setenv("SOVIET_ROOT", "/tmp/cccp-test/destination/", 1); + setenv("SOVIET_ENV_DIR", "/tmp/cccp-test/src_dir", 1); + setenv("SOVIET_TEST_ENV", "TEST", 1); + + pmkdir(getenv("SOVIET_ROOT")); + pmkdir("/tmp/cccp-test/spm_dir"); + pmkdir("/tmp/cccp-test/src_dir"); - init(); - struct package p = {0}; + setenv("SOVIET_FORMATS", "ecmp", 1); + setenv("SOVIET_PLUGIN_DIR", "/var/cccp/plugins", 1); - assert(open_pkg(spm_path, &p,NULL) == 0); + char TEST_BUILD_DIR[MAX_PATH]; + char TEST_MAKE_DIR[MAX_PATH]; + + sprintf(TEST_BUILD_DIR, "%s/%s", getenv("SOVIET_TEST_DIR"), "TEST_BUILD_DIR"); + sprintf(TEST_MAKE_DIR, "%s/%s", getenv("SOVIET_TEST_DIR"), "TEST_MAKE_DIR"); + + setenv("SOVIET_BUILD_DIR", TEST_BUILD_DIR, 1); + setenv("SOVIET_MAKE_DIR", TEST_MAKE_DIR, 1); - setenv("NAME", p.name, 1); - setenv("VERSION", p.version, 1); - if (p.url != NULL) { - parse_env(&(p.url)); - dbg(1, "URL: %s", p.url); - setenv("URL", p.url, 1); + pmkdir(getenv("SOVIET_BUILD_DIR")); + pmkdir(getenv("SOVIET_MAKE_DIR")); + pmkdir(getenv("SOVIET_ENV_DIR")); + + FILE *ptr; + ptr = fopen("/tmp/cccp-test/test.ecmp","w"); + fprintf( ptr, + "[info]\n" + "name = test\n" + "version = 0\n" + "type = src\n" + "[files]\n" + "$VERSION-file 127.0.0.1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n" + "[description]\n" + "test package\n" + "[config]\n" + "SOVIET_TEST_VAR=$SOVIET_TEST_ENV\n" + "[prepare]\n" + "mkdir test-0\n" + "mv 0-file ./test-0/0-file\n" + "[install]\n" + "mv 0-file $SOVIET_BUILD_DIR/0-file\n" + "[special]\n" + "echo special...\n" + ); + + fclose(ptr); } - char* legacy_dir = calloc(2048,1); - sprintf(legacy_dir,"%s/%s-%s",getenv("SOVIET_MAKE_DIR"),p.name,p.version); - - dbg(1,"Legacy dir: %s",legacy_dir); + struct package pkg = {0}; - assert(make(legacy_dir,&p) == 0); - - // Run 'install' command - if (p.info.install == NULL && strlen(p.info.install) == 0) { - msg(FATAL, "No install command!"); + pkg.name = strdup("test"); + pkg.path = strdup("test.ecmp"); + + result += open_pkg("/tmp/cccp-test", &pkg); + write_package_configuration_file(&pkg); + read_package_configuration_file(&pkg); + result += strcmp(getenv("SOVIET_TEST_VAR"), "TEST"); + if(result != 0) + { + msg(ERROR, "EXPECTED: 'TEST'"); + msg(ERROR, "GOT: '%s'", getenv("SOVIET_TEST_VAR")); + msg(FATAL, "FAILED"); } + result += install_package_source(&pkg); - char install_cmd[64 + strlen(legacy_dir) + strlen(p.info.install)]; - sprintf(install_cmd, "( cd %s && %s )", legacy_dir, p.info.install); + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); - dbg(2, "Executing install command: %s", install_cmd); - if (system(install_cmd) != 0) { - msg(FATAL, "Failed to install %s", p.name); - return -2; + // Cleanup + { + free_pkg(&pkg); + rmany(getenv("SOVIET_BUILD_DIR")); + rmany(getenv("SOVIET_MAKE_DIR")); + rmany(getenv("SOVIET_SPM_DIR")); + rmany(getenv("SOVIET_SOURCE_DIR")); + unsetenv("SOVIET_BUILD_DIR"); + unsetenv("SOVIET_MAKE_DIR"); + unsetenv("SOVIET_SPM_DIR"); + unsetenv("SOVIET_FORMATS"); + unsetenv("SOVIET_PLUGIN_DIR"); + unsetenv("SOVIET_TEST_ENV"); + unsetenv("SOVIET_TEST_VAR"); + rmany("/tmp/cccp-test/test.ecmp"); } - dbg(1, "Install command executed!"); - - dbg(1,"Getting locations for %s",p.name); - p.locationsCount = get_locations(&p.locations,getenv("SOVIET_BUILD_DIR")); - assert(p.locationsCount > 0); - - free_pkg(&p); - - dbg(1,"Got %d locations for %s",p.locationsCount,p.name); - - return; } -void test_split() { - - msg(INFO,"Testing 'split()'.."); +void test_make() +{ + int result = 0; - chdir(WORKING_DIR); - system("python3 gen_split.py split.txt 512"); - - char* split_str; - rdfile("split.txt",&split_str); - - char **split_list = NULL; - int count = splita(strdup(split_str),',',&split_list); - - char* str_split = assemble(split_list,count); - free(*split_list); - free(split_list); - - dbg(2, "str_split: %s", str_split); - dbg(2, "split_str: %s", split_str); - - assert(strcmp(str_split,split_str) == 0); + // Necessary prepwork + { + setenv("SOVIET_SOURCE_DIR", "/tmp/cccp-test/src_dir", 1); + pmkdir("/tmp/cccp-test/src_dir"); - free(split_str); - free(str_split); + setenv("SOVIET_FORMATS", "ecmp", 1); + setenv("SOVIET_PLUGIN_DIR", "/var/cccp/plugins", 1); - return; -} + char TEST_MAKE_DIR[MAX_PATH]; + sprintf(TEST_MAKE_DIR, "%s/%s", getenv("SOVIET_TEST_DIR"), "TEST_MAKE_DIR"); + setenv("SOVIET_MAKE_DIR", TEST_MAKE_DIR, 1); + pmkdir(getenv("SOVIET_MAKE_DIR")); + + FILE *ptr; + ptr = fopen("/tmp/cccp-test/test.ecmp","w"); + fprintf( ptr, + "[info]\n" + "name = test\n" + "version = 0\n" + "type = src\n" + "[files]\n" + "$VERSION-file 127.0.0.1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n" + "[prepare]\n" + "mkdir test-0\n" + "mv 0-file ./test-0/0-file\n" + ); + + fclose(ptr); + } -void test_config() { + struct package pkg = {0}; + pkg.name = strdup("test"); + pkg.path = strdup("test.ecmp"); + + result += open_pkg("/tmp/cccp-test", &pkg); + result += make(&pkg); + result += access("/tmp/cccp-test/TEST_MAKE_DIR/test-0/0-file", F_OK); - msg(INFO,"Testing 'readConfig()'.."); + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); - assert(readConfig(getenv("SOVIET_CONFIG_FILE"), 0) == 0); - return; + // Cleanup + { + free_pkg(&pkg); + rmany(getenv("SOVIET_MAKE_DIR")); + rmany(getenv("SOVIET_SOURCE_DIR")); + unsetenv("SOVIET_MAKE_DIR"); + unsetenv("SOVIET_FORMATS"); + unsetenv("SOVIET_PLUGIN_DIR"); + rmany("/tmp/cccp-test/test.ecmp"); + } } - -void test_get() { - - msg(INFO,"Testing 'get()'.."); - - char db_path[2048]; - sprintf(db_path,"%s/get_test.db",WORKING_DIR); - - setenv("ALL_DB_PATH",db_path,1); - repo_sync(); - - struct package base_pkg = {0}; - char base_path[2048]; - sprintf(base_path,"%s/test.base.ecmp",WORKING_DIR); - assert(open_ecmp(base_path,&base_pkg) == 0); - - - struct package t_pkg; - t_pkg.name = "test"; - - dbg(2,"Repo: %s",getenv("SOVIET_DEFAULT_REPO")); - - char out_test[2048+16 ] = {0}; - sprintf(out_test,"%s/test.ecmp",WORKING_DIR); - dbg(3,"Copying to %s",out_test); - remove(out_test); - char* fmt = get(&t_pkg,getenv("SOVIET_DEFAULT_REPO"),out_test); +void test_move() +{ + // Necessary prepwork + { + setenv("SOVIET_BUILD_DIR", "/tmp/cccp-test/source/", 1); + setenv("SOVIET_ROOT", "/tmp/cccp-test/destination/", 1); + pmkdir(getenv("SOVIET_BUILD_DIR")); + pmkdir(getenv("SOVIET_ROOT")); - assert(open_ecmp(out_test,&t_pkg) == 0); - - // print fmt and all package info - dbg(1,"fmt: %s",fmt); - dbg(1,"name: %s",t_pkg.name); - dbg(1,"version: %s",t_pkg.version); - dbg(1,"url: %s",t_pkg.url); + FILE *ptr; + ptr = fopen("/tmp/cccp-test/source/test","w"); + fprintf(ptr, "test file"); + fclose(ptr); + } - assert(strcmp(base_pkg.name,t_pkg.name) == 0); - assert(strcmp(base_pkg.version,t_pkg.version) == 0); - assert(strcmp(base_pkg.url,t_pkg.url) == 0); - // add other cmp later + int num_files; + char **files_array = get_all_files(getenv("SOVIET_BUILD_DIR"), getenv("SOVIET_BUILD_DIR"), &num_files); + move_binaries(files_array, num_files); - free_pkg(&base_pkg); - free_pkg(&t_pkg); + int result = access("/tmp/cccp-test/destination/test", F_OK); - return; + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); + // Cleanup + { + for(int i = 0; i < num_files; i++) + { + free(files_array[i]); + } + free(files_array); + rmany(getenv("SOVIET_BUILD_DIR")); + rmany(getenv("SOVIET_ROOT")); + unsetenv("SOVIET_ROOT"); + unsetenv("SOVIET_ROOT"); + } } -void test_ecmp(char* spm_path) { - - msg(INFO,"Testing 'open_ecmp()' and 'create_ecmp()'.."); +void test_pkg() +{ + int result = 0; + // Test package array + { + struct packages* pkgs = create_pkgs(0); + for(int i = 0; i < 5; i++) + { + struct package pkg = {0}; + pkg.name = strdup("test_part_1"); + pkg.description = strdup("test description"); + push_pkg(pkgs, &pkg); + } + result += (pkgs->count - 5); + dbg(2, "size %d - count %d", pkgs->size, pkgs->count); + + struct packages* t_pkgs = create_pkgs(0); + for(int i = 0; i < 5; i++) + { + struct package pkg = {0}; + pkg.name = strdup("test_part_2"); + pkg.description = strdup("test description"); + push_pkg(t_pkgs, &pkg); + } + result += (t_pkgs->count - 5); + dbg(2, "size %d - count %d", t_pkgs->size, t_pkgs->count); + + merge_pkgs(pkgs, t_pkgs); + result += (pkgs->count - 10); + dbg(2, "size %d - count %d", pkgs->size, pkgs->count); + + dbg(2, "result: %d ", result); + // Cleanup + { + free_pkgs(pkgs); + } + } - setenv("FORMATS","ecmp",1); + // Test create and open package + { + // Necessary prepwork + { + setenv("SOVIET_SPM_DIR", "/tmp/cccp-test/spm_dir", 1); + pmkdir("/tmp/cccp-test/spm_dir"); + + setenv("SOVIET_FORMATS", "ecmp", 1); + setenv("SOVIET_PLUGIN_DIR", "/var/cccp/plugins", 1); + + FILE *ptr; + ptr = fopen("/tmp/cccp-test/test.ecmp","w"); + fprintf( ptr, + "[info]\n" + "name = test\n" + "version = 0\n" + "type = src\n" + "[files]\n" + "$VERSION-file 127.0.0.1 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\n" + "[description]\n" + "test package\n" + "[config]\n" + "SOVIET_TEST_VAR=$SOVIET_TEST_ENV\n" + "[prepare]\n" + "mkdir test-0\n" + "mv 0-file ./test-0/0-file\n" + "[install]\n" + "mv 0-file $SOVIET_BUILD_DIR/0-file\n" + "[special]\n" + "echo special...\n" + ); + + fclose(ptr); + } + + struct package pkg_0 = {0}; + pkg_0.path = "test-0.ecmp"; + pkg_0.name = "test"; + pkg_0.version = "0"; + pkg_0.type = "src"; + pkg_0.description= "test package\n"; + result += create_pkg("/tmp/cccp-test", &pkg_0); + + struct package pkg_1 = {0}; + pkg_1.name = strdup("test"); + pkg_1.path = strdup("test-0.ecmp"); + result += open_pkg("/tmp/cccp-test", &pkg_1); + result += strcmp(pkg_1.name, "test"); + result += strcmp(pkg_1.version, "0"); + result += strcmp(pkg_1.type, "src"); + result += strcmp(pkg_1.description, "test package\n"); + dbg(2, "Finished testing create and open package"); + dbg(2, "result: %d ", result); + + // Cleanup + { + free_pkg(&pkg_1); + rmany(getenv("SOVIET_SPM_DIR")); + unsetenv("SOVIET_SPM_DIR"); + unsetenv("SOVIET_FORMATS"); + unsetenv("SOVIET_PLUGIN_DIR"); + rmany("/tmp/cccp-test/test.ecmp"); + rmany("/tmp/cccp-test/test-0.ecmp"); + } + } - struct package old_pkg = {0}; + // Test package database + { + // Necessary prepwork + { + setenv("SOVIET_REPOS_DIR", "/tmp/cccp-test/repo_dir", 1); + setenv("SOVIET_SPM_DIR", "/tmp/cccp-test/spm_dir", 1); + setenv("SOVIET_DEFAULT_FORMAT", "ecmp", 1); + + pmkdir(getenv("SOVIET_REPOS_DIR")); + pmkdir("/tmp/cccp-test/repo_dir/test_repo/long/repo/file/tree"); + pmkdir(getenv("SOVIET_SPM_DIR")); + for(int i = 0; i < 10; i++) + { + char dir[MAX_PATH]; + sprintf(dir, "%s/%s/%d%s", getenv("SOVIET_REPOS_DIR"), "test_repo/long/repo/file/tree", i, ".ecmp"); + + FILE *ptr; + ptr = fopen(dir,"w"); + fprintf(ptr, "test file"); + fclose(ptr); + } + // Garbage files + for(int i = 0; i < 10; i++) + { + char dir[MAX_PATH]; + sprintf(dir, "%s/%s/%s-%d", getenv("SOVIET_REPOS_DIR"), "test_repo/long/repo/file/tree", ".ecmp", i); + + FILE *ptr; + ptr = fopen(dir,"w"); + fprintf(ptr, "test file"); + fclose(ptr); + } + } + + // Get packages + struct packages* pkgs = get_pkgs("/tmp/cccp-test/repo_dir/"); + // there should be 10 packages in that directory + result += (pkgs->count - 10); + for(int i = 0; i < 10; i++) + { + char str[8]; + sprintf(str, "%d", i); + // all the found packages should be 0-9 + result += strcmp(pkgs->buffer[i].name, str); + } + + // Create a database + result += create_pkg_db("/tmp/cccp-test/test.db", pkgs); + + // Preform a search + struct packages* search_result = search_pkgs("/tmp/cccp-test/test.db", "1"); + // we should find only one '1' + result += (search_result->count - 1); + result += strcmp(search_result->buffer[0].path, "test_repo/long/repo/file/tree/1.ecmp"); + + struct packages* db_pkgs = dump_db("/tmp/cccp-test/test.db"); + // there should be 10 packages in the database + result += (db_pkgs->count - 10); + dbg(2, "Finished testing package database"); + + // Cleanup + { + free_pkgs(pkgs); + free_pkgs(db_pkgs); + free_pkgs(search_result); + rmany(getenv("SOVIET_REPOS_DIR")); + rmany(getenv("SOVIET_SPM_DIR")); + rmany("/tmp/cccp-test/test.db"); + unsetenv("SOVIET_REPOS_DIR"); + unsetenv("SOVIET_DEFAULT_FORMAT"); + unsetenv("SOVIET_SPM_DIR"); + } + } - assert(open_ecmp(spm_path,&old_pkg) == 0); + // Test updating packages + { + // Necessary prepwork + { + setenv("SOVIET_REPOS_DIR", "/tmp/cccp-test/repo_dir", 1); + setenv("SOVIET_SPM_DIR", "/tmp/cccp-test/spm_dir", 1); + setenv("SOVIET_DEFAULT_FORMAT", "ecmp", 1); + setenv("SOVIET_FORMATS", "ecmp", 1); + setenv("SOVIET_PLUGIN_DIR", "/var/cccp/plugins", 1); + + pmkdir(getenv("SOVIET_REPOS_DIR")); + pmkdir("/tmp/cccp-test/repo_dir/test_repo/long/repo/file/tree"); + + pmkdir(getenv("SOVIET_SPM_DIR")); + pmkdir("/tmp/cccp-test/spm_dir/test_repo/long/repo/file/tree"); + + // File 1 - outdated + { + char spm_dir[MAX_PATH]; + char repo_dir[MAX_PATH]; + sprintf(repo_dir, "%s/%s/%s", getenv("SOVIET_REPOS_DIR"), "test_repo/long/repo/file/tree", "outdated.ecmp"); + sprintf(spm_dir, "%s/%s/%s", getenv("SOVIET_SPM_DIR"), "test_repo/long/repo/file/tree", "outdated.ecmp"); + + FILE *ptr; + ptr = fopen(repo_dir,"w"); + fprintf(ptr, "[info]\n"); + fprintf(ptr, "name = outdated\n"); + fprintf(ptr, "version = 1\n"); + fclose(ptr); + + ptr = fopen(spm_dir,"w"); + fprintf(ptr, "[info]\n"); + fprintf(ptr, "name = outdated\n"); + fprintf(ptr, "version = 0\n"); + fclose(ptr); + } + + // File 2 - same + { + char spm_dir[MAX_PATH]; + char repo_dir[MAX_PATH]; + sprintf(repo_dir, "%s/%s/%s", getenv("SOVIET_REPOS_DIR"), "test_repo/long/repo/file/tree", "same.ecmp"); + sprintf(spm_dir, "%s/%s/%s", getenv("SOVIET_SPM_DIR"), "test_repo/long/repo/file/tree", "same.ecmp"); + + FILE *ptr; + ptr = fopen(repo_dir,"w"); + fprintf(ptr, "[info]\n"); + fprintf(ptr, "name = same\n"); + fprintf(ptr, "version = 1\n"); + fclose(ptr); + + ptr = fopen(spm_dir,"w"); + fprintf(ptr, "[info]\n"); + fprintf(ptr, "name = same\n"); + fprintf(ptr, "version = 1\n"); + fclose(ptr); + } + + // File 3 - local only + { + char spm_dir[MAX_PATH]; + sprintf(spm_dir, "%s/%s/%s", getenv("SOVIET_SPM_DIR"), "test_repo/long/repo/file/tree", "local.ecmp"); + + FILE *ptr; + ptr = fopen(spm_dir,"w"); + fprintf(ptr, "[info]\n"); + fprintf(ptr, "name = local\n"); + fprintf(ptr, "version = 1\n"); + fclose(ptr); + } + + struct packages* installed = get_pkgs(getenv("SOVIET_SPM_DIR")); + struct packages* remote = get_pkgs(getenv("SOVIET_REPOS_DIR")); + + setenv("SOVIET_ALL_DB", "/tmp/cccp-test/all.db", 1); + setenv("SOVIET_INSTALLED_DB", "/tmp/cccp-test/installed.db", 1); + + create_pkg_db(getenv("SOVIET_ALL_DB"), remote); + create_pkg_db(getenv("SOVIET_INSTALLED_DB"), installed); + + free_pkgs(installed); + free_pkgs(remote); + } - // print the pkg - dbg(2,"old_pkg: %s => %s %s\n",old_pkg.name,old_pkg.version,old_pkg.type); - - msg(INFO,"Creating ecmp package file"); + struct packages* need_updating = update_pkg(); + // We expect only one of the packages to need updating + result += (need_updating->count - 1); + dbg(2, "Finished testing package update"); + + result += strcmp(need_updating->buffer[0].name, "outdated"); + result += strcmp(need_updating->buffer[0].version, "1"); + + // Cleanup + { + free_pkgs(need_updating); + + rmany(getenv("SOVIET_REPOS_DIR")); + rmany(getenv("SOVIET_SPM_DIR")); + rmany(getenv("SOVIET_ALL_DB")); + rmany(getenv("SOVIET_INSTALLED_DB")); + + unsetenv("SOVIET_REPOS_DIR"); + unsetenv("SOVIET_SPM_DIR"); + unsetenv("SOVIET_DEFAULT_FORMAT"); + unsetenv("SOVIET_FORMATS"); + unsetenv("SOVIET_PLUGIN_DIR"); + unsetenv("SOVIET_ALL_DB"); + unsetenv("SOVIET_INSTALLED_DB"); + } + } + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); +} - char mod_path[2048]; - sprintf(mod_path,"%s.mod",spm_path); +void test_repo() +{ + int result = 0; + // Necessary prepwork + { + setenv("SOVIET_REPOS_DIR", "/tmp/cccp-test/repo_dir", 1); + setenv("SOVIET_DEFAULT_REPO_URL", "https://github.com/Soviet-Linux/OUR.git", 1); + setenv("SOVIET_DEFAULT_REPO", "OUR", 1); + setenv("SOVIET_DEFAULT_FORMAT", "ecmp", 1); - assert(create_ecmp(mod_path, &old_pkg) == 0); + pmkdir("/tmp/cccp-test/repo_dir/repo-1"); + pmkdir("/tmp/cccp-test/repo_dir/repo-2"); + pmkdir("/tmp/cccp-test/repo_dir/repo-3"); - // now reopen package and compare - struct package new_pkg = {0}; + git_libgit2_init(); + } - assert(open_ecmp(mod_path,&new_pkg) == 0); + int repo_count; + char** REPOS = get_repos(&repo_count); + // we expect 3 repos + 1 local; + result += (repo_count - 4); + result += repo_sync(); - // print the pkg - dbg(2,"new_pkg: %s => %s %s\n",new_pkg.name,new_pkg.version,new_pkg.type); + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); - // compare packages - assert(strcmp(new_pkg.name,old_pkg.name) == 0); - assert(strcmp(new_pkg.version,old_pkg.version) == 0); - assert(strcmp(new_pkg.type,old_pkg.type) == 0); + // Cleanup + { + git_libgit2_shutdown(); + + for(int i = 0; i < 4; i++) + { + free(REPOS[i]); + } + free(REPOS); + rmany("/tmp/cccp-test/repo_dir"); + unsetenv("SOVIET_REPOS_DIR"); + unsetenv("SOVIET_DEFAULT_REPO_URL"); + unsetenv("SOVIET_DEFAULT_REPO"); + unsetenv("SOVIET_DEFAULT_FORMAT"); + } +} - // free packages - free_pkg(&old_pkg); - free_pkg(&new_pkg); +void test_uninstall() +{ + // Necessary prepwork + { + setenv("SOVIET_SPM_DIR", "/tmp/cccp-test", 1); + setenv("SOVIET_FORMATS", "ecmp", 1); + setenv("SOVIET_PLUGIN_DIR", "/var/cccp/plugins", 1); + setenv("SOVIET_ROOT", "/", 1); + + FILE *ptr; + ptr = fopen("/tmp/cccp-test/test.ecmp","w"); + fprintf(ptr, "[locations]\n"); + fprintf(ptr, "/tmp/cccp-test/test.ecmp\n"); + fclose(ptr); + } - remove(mod_path); + struct package pkg = {0}; + pkg.path = strdup("test.ecmp"); + int result = uninstall(&pkg); + free_pkg(&pkg); - return; -} + if(result != 0) msg(FATAL, "FAILED"); + else msg(INFO, "PASSED"); -char* assemble(char** list,int count) { - dbg(3,"Assembling %d strings",count); - char* string = calloc(2048*count,sizeof(char)); - int i; - for (i = 0; i < count-1; i++) + // Cleanup { - strcat(string,list[i]); - strcat(string,","); - + unsetenv("SOVIET_SPM_DIR"); + unsetenv("SOVIET_ROOT"); + unsetenv("SOVIET_FORMATS"); + unsetenv("SOVIET_PLUGIN_DIR"); } - strcat(string,list[i]); - return string; -} +} \ No newline at end of file diff --git a/test/test.h b/test/test.h index 208b4fb..1d0e6a7 100644 --- a/test/test.h +++ b/test/test.h @@ -7,18 +7,16 @@ #include "../include/globals.h" #include "../include/cutils.h" - -#define STATIC - - -void test_move(); -void test_get(); -void test_split(); +void test_check(); +void test_clean(); void test_config(); - -void test_ecmp(char* spm_path); -void test_make(char* spm_path); -void test_pm(char* spm_path); - -extern char WORKING_DIR[2048]; +void test_globals(); +void test_init(); +void test_install(); +void test_make(); +void test_move(); +void test_pkg(); +void test_repo(); +void test_uninstall(); +void test_util();