Add file locking capabilities

This commit is contained in:
Liam Waldron 2025-04-03 15:07:08 -04:00
parent 1ed2fd33f0
commit 9fcbbf3192
10 changed files with 645 additions and 498 deletions

BIN
build/lib/libglacier.a Normal file

Binary file not shown.

BIN
build/lib/libglacier.o Normal file

Binary file not shown.

View File

@ -26,67 +26,48 @@
#endif #endif
/* /*
* init_config * gl_init_config
* *
* DESCRIPTION: Initialize libconfig with required configs * DESCRIPTION: Initialize libconfig.
* PARAMETERS: * PARAMETERS: None.
* None. * RETURNS: 0 on success, EXIT_FAILURE on error
* RETURN VALUES:
* 0 on success, 1 on failure
* CAVEATS:
* This MUST be called before ANY other config function is.
* EXAMPLE:
* init_config();
*/ */
int gl_init_config(void);
int init_config(void);
/* /*
* die_config * gl_die_config
* *
* DESCRIPTION: Die_config brings down libconfig gracefully. * DESCRIPTION: Kill libconfig.
* PARAMETERS: * PARAMETERS: None.
* None. * RETURNS: EXIT_SUCCESS on success
* RETURN VALUES:
* 0 on success, 1 on failure
* CAVEATS:
* This MUST be called after ALL other config functions have completed.
* EXAMPLE:
* die_config();
*/ */
int gl_die_config(void);
int die_config(void);
/* /*
* load_all_from_config * gl_load_all_from_config
* *
* DESCRIPTION: load_all_from_config loads all settings from the config file. * DESCRIPTION: Loads all settings from the Glacier config file.
* PARAMETERS: * PARAMETERS: None.
* None. * RETURNS: 0 on success, 1 on error
* RETURN VALUES:
* 0 on success, 1 on failure
* CAVEATS:
* None.
* EXAMPLE:
* load_all_from_config();
*/ */
int gl_load_all_from_config(void);
int load_all_from_config(void);
/* /*
* load_all_from_profile * gl_load_all_from_profile
* *
* DESCRIPTION: load_all_from_profile loads all settings from the profile file. * DESCRIPTION: Loads all settings from the Glacier system profile.
* PARAMETERS: * PARAMETERS: None.
* None. * RETURNS: 0 on success, 1 on error
* RETURN VALUES:
* 0 on success, 1 on failure
* CAVEATS:
* None.
* EXAMPLE:
* load_all_from_profile();
*/ */
int gl_load_all_from_profile(void);
int load_all_from_profile(void); /*
* gl_load_setting_from_config
*
* DESCRIPTION: Load a specified setting from the Glacier config file.
* PARAMETERS: char SETTING[]
* RETURNS: 0 on success, 1 on error
*/
int gl_load_setting_from_config(char SETTING[]);
#endif #endif

View File

@ -36,69 +36,39 @@ struct node {
}; };
/* /*
* create_node * gl_create_node
* *
* DESCRIPTION: Create_node creates a node for a dependency tree data structure. * DESCRIPTION: Create a dependency tree node.
* PARAMETERS: * PARAMETERS: char *data
* char *data -> The name of the node to create * RETURNS: struct node* on success, NULL on failure
* RETURN VALUES:
* A pointer to the created node on success, NULL on failure
* CAVEATS:
* Caller must free the node using free_node when done
* EXAMPLE:
* struct node *package = create_node("Package");
*/ */
struct node *gl_create_node(char *data);
struct node *create_node(char *data);
/* /*
* free_node * gl_free_node
* *
* DESCRIPTION: Free_node recursively frees all memory allocated for a node and its children. * DESCRIPTION: Recursively free a node and all its children.
* PARAMETERS: * PARAMETERS: struct node *root
* struct node *root -> The root node to free * RETURNS: void
* RETURN VALUES:
* None.
* CAVEATS:
* Will free all child nodes recursively.
* EXAMPLE:
* free_node(package);
*/ */
void gl_free_node(struct node *root);
void free_node(struct node *root);
/* /*
* add_child * gl_add_child
* *
* DESCRIPTION: Add_child adds a child node to a parent node. * DESCRIPTION: Add a child node to a parent node.
* PARAMETERS: * PARAMETERS: struct node *parent, struct node *child
* struct node *parent -> The parent node which the child will be added to * RETURNS: 0 on success, 1 on NULL pointer, 2 on invalid numChildren, 3 on max children exceeded
* struct node *child -> The child node which will be added to the parent node
* RETURN VALUES:
* 0 on success, 1-3 for different error conditions
* CAVEATS:
* None.
* EXAMPLE:
* add_child(package, dep1);
*/ */
int gl_add_child(struct node *parent, struct node *child);
int add_child(struct node *parent, struct node *child);
/* /*
* print_tree * gl_print_tree
* *
* DESCRIPTION: Print_tree prints a dependency tree specified at its root node. * DESCRIPTION: Print a dependency tree.
* PARAMETERS: * PARAMETERS: struct node *root, int level
* struct node *root -> The tree to print * RETURNS: 0 on success, 1 on invalid level, 2 on max recursion depth exceeded, 3 on invalid numChildren, 4 on child print error
* int level -> The number of levels to descend
* RETURN VALUES:
* 0 on success, non-zero on error
* CAVEATS:
* None.
* EXAMPLE:
* print_tree(package, 0);
*/ */
int gl_print_tree(struct node *root, int level);
int print_tree(struct node *root, int level);
#endif #endif

View File

@ -19,81 +19,73 @@
#define GLACIERLOG_H_ #define GLACIERLOG_H_
/* /*
* infolog * gl_infolog
* *
* DESCRIPTION: Infolog outputs a stylized info message. It follows Glacier's uniform CLI style. * DESCRIPTION: gl_infolog outputs a stylized info message. It follows Glacier's uniform CLI style.
* PARAMETERS: * PARAMETERS:
* char MSG[] -> The message to output * char MSG[] -> The message to output
* RETURN VALUES: * RETURN VALUES:
* None. * None.
* CAVEATS: * CAVEATS:
* * Cannot output variables. If you must output variables, use printf instead. * None.
* * A NEWLINE ('\n') character is implied, therefore putting one at the end of
* a string is not needed.
* EXAMPLE: * EXAMPLE:
* infolog("This is an info message."); * gl_infolog("This is an info message.");
*/ */
void infolog(char MSG[]); void gl_infolog(char MSG[]);
/**************************************************************************************************************/ /**************************************************************************************************************/
/* /*
* warnlog * gl_warnlog
* *
* DESCRIPTION: Warnlog outputs a stylized warning message. It follows Glacier's uniform CLI style. * DESCRIPTION: gl_warnlog outputs a stylized warning message. It follows Glacier's uniform CLI style.
* PARAMETERS: * PARAMETERS:
* char MSG[] -> The message to output * char MSG[] -> The message to output
* RETURN VALUES: * RETURN VALUES:
* None. * None.
* CAVEATS: * CAVEATS:
* * Cannot output variables. If you must output variables, use printf instead. * None.
* * A NEWLINE ('\n') character is implied, therefore putting one at the end of
* a string is not needed.
* EXAMPLE: * EXAMPLE:
* warnlog("This is a warning message."); * gl_warnlog("This is a warning message.");
*/ */
void warnlog(char MSG[]); void gl_warnlog(char MSG[]);
/**************************************************************************************************************/ /**************************************************************************************************************/
/* /*
* errlog * gl_errlog
* *
* DESCRIPTION: Errlog outputs a stylized error message. It follows Glacier's uniform CLI style. * DESCRIPTION: gl_errlog outputs a stylized error message. It follows Glacier's uniform CLI style.
* PARAMETERS: * PARAMETERS:
* char MSG[] -> The message to output * char MSG[] -> The message to output
* RETURN VALUES: * RETURN VALUES:
* None. * None.
* CAVEATS: * CAVEATS:
* * Cannot output variables. If you must output variables, use printf instead. * None.
* * A NEWLINE ('\n') character is implied, therefore putting one at the end of
* a string is not needed.
* EXAMPLE: * EXAMPLE:
* errlog("This is an error message."); * gl_errlog("This is an error message.");
*/ */
void errlog(char MSG[]); void gl_errlog(char MSG[]);
/**************************************************************************************************************/ /**************************************************************************************************************/
/* /*
* successlog * gl_successlog
* *
* DESCRIPTION: Successlog outputs a stylized success message. It follows Glacier's uniform CLI style. * DESCRIPTION: gl_successlog outputs a stylized success message. It follows Glacier's uniform CLI style.
* PARAMETERS: * PARAMETERS:
* char MSG[] -> The message to output * char MSG[] -> The message to output
* RETURN VALUES: * RETURN VALUES:
* None. * None.
* CAVEATS: * CAVEATS:
* * Cannot output variables. If you must output variables, use printf instead. * None.
* * A NEWLINE ('\n') character is implied, therefore putting one at the end of
* a string is not needed.
* EXAMPLE: * EXAMPLE:
* successlog("This is a success message."); * gl_successlog("This is a success message.");
*/ */
void successlog(char MSG[]); void gl_successlog(char MSG[]);
#endif #endif

View File

@ -25,54 +25,77 @@
#define PATH_MAX_SIZE 512 #define PATH_MAX_SIZE 512
/* /*
* mkworkspace * gl_mkworkspace
*
* DESCRIPTION: gl_mkworkspace prepares /tmp/glacier-workspace for an operation
* *
* DESCRIPTION: Mkworkspace prepares /tmp/glacier-workspace for an operation
* PARAMETERS:
* None.
* RETURN VAUES:
* 0 on workspace already exists, 1 on workspace created, -1 on error
* CAVEATS:
* None.
* EXAMPLE: * EXAMPLE:
* mkworkspace(); * gl_mkworkspace();
*
* RETURNS: 0 on success, 1 if workspace already exists, -1 on failure
*/ */
int gl_mkworkspace(void);
int mkworkspace(void);
/* /*
* prepare_pkg * gl_prepare_pkg
*
* DESCRIPTION: gl_prepare_pkg copies a package archive from the localdb, and untars it
* *
* DESCRIPTION: Prepare_pkg copies a package archive from the localdb, and untars it
* PARAMETERS:
* char PACKAGE[] -> The package file to prepare
* RETURN VAUES:
* 0 on success, 1 on package does not exist or error, other values for specific errors
* CAVEATS:
* The example presented is bad. You should be calling the system profile variable
* rather than manually specifying one.
* EXAMPLE: * EXAMPLE:
* prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar"); * gl_prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar");
*
* RETURNS: 0 on success, 1 on failure
*/ */
int gl_prepare_pkg(char PACKAGE[]);
int prepare_pkg(char PACKAGE[]);
/* /*
* run_make_task * gl_run_make_task
*
* DESCRIPTION: gl_run_make_task runs a specified make task in a package's current working directory
* *
* DESCRIPTION: Run_make_task runs a specified make task in a package's current working directory
* PARAMETERS:
* char TASK[] -> The make task to run
* RETURN VAUES:
* 0 on success, other values for specific errors
* CAVEATS:
* MUST be run after prepare_pkg(), or else errors will occur
* Same caveat as above. Do not manually specify the system profile, use its variable.
* EXAMPLE: * EXAMPLE:
* prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar"); * MUST be run after gl_prepare_pkg(), or else errors will occur
* run_make_task("installpkg"); * gl_prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar");
* gl_run_make_task("installpkg");
*
* RETURNS: 0 on success, 1 on failure
*/
int gl_run_make_task(char TASK[]);
/*
* gl_lock_file
*
* DESCRIPTION: Locks a specified file using fcntl
* PARAMETERS:
* const char *filepath -> The path to the file to lock
* RETURN VALUES:
* File descriptor on success, -1 on failure
* CAVEATS:
* The returned file descriptor must be passed to gl_unlock_file() to release the lock
* EXAMPLE:
* int fd = gl_lock_file("/path/to/file");
* if (fd >= 0) {
* // Do work with locked file
* gl_unlock_file(fd);
* }
*/ */
int run_make_task(char TASK[]); int gl_lock_file(const char *filepath);
/*
* gl_unlock_file
*
* DESCRIPTION: Unlocks a specified file using fcntl
* PARAMETERS:
* int file_descriptor -> The file descriptor returned by gl_lock_file()
* RETURN VALUES:
* 0 on success, 1 on failure
* CAVEATS:
* Only the process that acquired the lock can release it
* EXAMPLE:
* gl_unlock_file(file_descriptor);
*/
int gl_unlock_file(int file_descriptor);
#endif #endif

View File

@ -19,68 +19,48 @@
#define GLACIERRUNTIME_H_ #define GLACIERRUNTIME_H_
/* /*
* runtime_exists * gl_runtime_exists
* *
* DESCRIPTION: runtime_exists checks if all necessary runtime files exist. * DESCRIPTION: Check if necessary runtime files exist.
* PARAMETERS: * PARAMETERS: None.
* None. (void) * RETURNS: 1 if all files exist, 0 if any file is missing
* RETURN VALUES:
* 0 on one or more runtime files missing, 1 on all runtime files exist
* CAVEATS:
* None.
* EXAMPLE:
* if (runtime_exists() == 0) {
* errlog("One or more runtime files missing");
* return 1;
* }
* else {
* successlog("All runtime files present");
* return 0;
* }
*/ */
int gl_runtime_exists(void);
int runtime_exists(void);
/* /*
* is_process_root * gl_is_process_root
* *
* DESCRIPTION: is_process_root checks if the process is running with root privileges. * DESCRIPTION: Check if process is running as root.
* PARAMETERS: * PARAMETERS: None.
* None. (void) * RETURNS: 1 if running as root, 0 otherwise
* RETURN VALUES:
* 0 on process is not running as root, 1 on process is running as root
* CAVEATS:
* None.
* EXAMPLE:
* // Assuming block is running within main(), no values will be returned.
* // If you wish to exit the program if it is not running as root, it would
* // be appropriate to add return values to this block
*
* if (is_process_root() == 0) {
* errlog("Process is not running as root");
* }
* else {
* successlog("Process is running as root");
* }
*/ */
int gl_is_process_root(void);
int is_process_root(void);
/* /*
* get_system_profile * gl_get_system_profile
* *
* DESCRIPTION: get_system_profile fetches the system profile, which contains information about the architecture and libc implementation. * DESCRIPTION: Get the current system profile.
* PARAMETERS: * PARAMETERS: None.
* None. (void) * RETURNS: char* containing the system profile name
* RETURN VALUES:
* A pointer to a string containing the system profile (e.g., "x86_64-musl").
* CAVEATS:
* None.
* EXAMPLE:
* char *profile = get_system_profile();
* infolog(profile);
*/ */
char *gl_get_system_profile(void);
char *get_system_profile(void); /*
* gl_lock_file
*
* DESCRIPTION: Locks a specified file using fcntl.
* PARAMETERS: const char *filepath - Path to the file to lock
* RETURNS: file descriptor on success, -1 on failure
*/
int gl_lock_file(const char *filepath);
/*
* gl_unlock_file
*
* DESCRIPTION: Unlocks a specified file using fcntl.
* PARAMETERS: int file_descriptor - The file descriptor of the locked file
* RETURNS: 0 on success, -1 on failure
*/
int gl_unlock_file(int file_descriptor);
#endif #endif

View File

@ -39,101 +39,48 @@ typedef unsigned char uchar;
/* int compare_file_hash(char ORIG_HASH[], char FILE[]); */ /* int compare_file_hash(char ORIG_HASH[], char FILE[]); */
/* /*
* hash_file * gl_print_hash
*
* DESCRIPTION: Prints a specified hash string
* PARAMETERS: unsigned char *hash, unsigned int length
* RETURNS: 0 on success, 1 on error
*/
int gl_print_hash(uchar *hash, uint length);
/*
* gl_stash_hash
*
* DESCRIPTION: Stores a hash inside a string
* PARAMETERS: unsigned char *stored_hash, unsigned char *hash, unsigned int length
* RETURNS: 0 on success, 1 on error
*/
int gl_stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, uint length);
/*
* gl_hash_file
* *
* DESCRIPTION: Performs a hashing operation on a file and stores the result * DESCRIPTION: Performs a hashing operation on a file and stores the result
* PARAMETERS: * PARAMETERS: const char *filename, unsigned char *out_hash, unsigned int *out_length
* const char *filename -> The file to hash * RETURNS: 0 on success, 1-6 for different error conditions
* unsigned char *out_hash -> Buffer to store the resulting hash
* unsigned int *out_length -> Will contain the length of the hash
* RETURN VALUES:
* 0 on success, other values for specific errors
* CAVEATS:
* out_hash buffer must be large enough to hold the hash (EVP_MAX_MD_SIZE recommended)
* EXAMPLE:
* unsigned char hash[EVP_MAX_MD_SIZE];
* unsigned int hash_len;
* hash_file("file.txt", hash, &hash_len);
*/ */
int gl_hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_length);
int hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_length);
/* /*
* print_hash * gl_verify_signature
* *
* DESCRIPTION: Prints a specified hash string to stdout * DESCRIPTION: Verify a package signature against a trusted keyring
* PARAMETERS: * PARAMETERS: char PACKAGE[], char SIGNATURE[]
* unsigned char *hash -> The hash to print * RETURNS: 0 on success, 1 on verification failure, 2 on file not found
* unsigned int length -> Length of the hash
* RETURN VALUES:
* 0 on success, 1 on error
* CAVEATS:
* None
* EXAMPLE:
* print_hash(hash, hash_len);
*/ */
int gl_verify_signature(char PACKAGE[], char SIGNATURE[]);
int print_hash(uchar *hash, uint length);
/* /*
* stash_hash * gl_check_integrity
* *
* DESCRIPTION: Stores a hash inside a string as hexadecimal representation * DESCRIPTION: Check package integrity by comparing with expected hash
* PARAMETERS: * PARAMETERS: char PACKAGE[], char EXPECTED_HASH[]
* char *stored_hash -> Buffer to store the resulting hash string * RETURNS: 0 on success, 1 on hash mismatch, 2 on file not found or error
* unsigned int stored_hash_size -> Size of the stored_hash buffer
* const uchar *hash -> The hash to convert to string
* uint length -> Length of the hash
* RETURN VALUES:
* 0 on success, 1 on error
* CAVEATS:
* stored_hash buffer must be at least (length*2)+1 bytes in size
* EXAMPLE:
* char hash_str[65]; // 32 bytes SHA-256 = 64 hex chars + null terminator
* stash_hash(hash_str, sizeof(hash_str), hash, hash_len);
*/ */
int gl_check_integrity(char PACKAGE[], char EXPECTED_HASH[]);
int stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, uint length);
/*
* verify_signature
*
* DESCRIPTION: Checks if a package's signature is valid against the trusted keyring
* PARAMETERS:
* char PACKAGE[] -> The package file to verify
* char SIGNATURE[] -> The signature file to check against
* RETURN VALUES:
* 0 on valid signature, 1 on invalid signature, 2 on file not found
* CAVEATS:
* None
* EXAMPLE:
* if (verify_signature("package.tar", "package.tar.sig") != 0) {
* errlog("invalid package signature");
* return(EXIT_FAILURE);
* }
*/
int verify_signature(char PACKAGE[], char SIGNATURE[]);
/*
* check_integrity
*
* DESCRIPTION: Verifies a package's SHA256 checksum against the expected value
* PARAMETERS:
* char PACKAGE[] -> The package file to check
* char EXPECTED_HASH[] -> The expected SHA256 hash
* RETURN VALUES:
* 0 on hash match, 1 on hash mismatch, 2 on file not found or hash calculation error
* CAVEATS:
* None
* EXAMPLE:
* char *expected = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592";
* if (check_integrity("package.tar", expected) != 0) {
* errlog("package integrity check failed");
* return(EXIT_FAILURE);
* }
*/
int check_integrity(char PACKAGE[], char EXPECTED_HASH[]);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -41,17 +41,17 @@ test_is_process_root(void)
void void
test_init_config(void) test_init_config(void)
{ {
CU_ASSERT_TRUE(init_config()); CU_ASSERT_TRUE(gl_init_config());
} }
void void
test_verify_signature(void) test_verify_signature(void)
{ {
/* This test assumes that both files exist in the test environment */ /* This test assumes that both files exist in the test environment */
CU_ASSERT_EQUAL(verify_signature("test_files/package.tar", "test_files/package.tar.sig"), 0); CU_ASSERT_EQUAL(gl_verify_signature("test_files/package.tar", "test_files/package.tar.sig"), 0);
/* Test with non-existent files */ /* Test with non-existent files */
CU_ASSERT_EQUAL(verify_signature("non_existent_file.tar", "non_existent_file.tar.sig"), 2); CU_ASSERT_EQUAL(gl_verify_signature("non_existent_file.tar", "non_existent_file.tar.sig"), 2);
} }
void void
@ -59,10 +59,10 @@ test_check_integrity(void)
{ {
/* This test assumes that test_files/package.tar exists in the test environment /* This test assumes that test_files/package.tar exists in the test environment
with a known hash value for testing */ with a known hash value for testing */
char *valid_hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; /* Empty file hash */ const char *valid_hash = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592";
/* Test file existence check */ /* Test file existence check */
CU_ASSERT_EQUAL(check_integrity("non_existent_file.tar", valid_hash), 2); CU_ASSERT_EQUAL(gl_check_integrity("test_files/package.tar", valid_hash), 0);
/* Note: For actual hash comparison testing, we would need a real file with known hash. /* Note: For actual hash comparison testing, we would need a real file with known hash.
These tests would need to be adjusted with real files and hashes for proper testing. */ These tests would need to be adjusted with real files and hashes for proper testing. */
@ -71,12 +71,12 @@ test_check_integrity(void)
void void
test_get_system_profile(void) test_get_system_profile(void)
{ {
/* Ensure that get_system_profile doesn't return NULL */ /* Ensure that gl_get_system_profile doesn't return NULL */
CU_ASSERT_PTR_NOT_NULL(get_system_profile()); CU_ASSERT_PTR_NOT_NULL(gl_get_system_profile());
/* Ensure the profile format seems correct (contains a dash) */ const char *profile = gl_get_system_profile();
const char *profile = get_system_profile(); CU_ASSERT_PTR_NOT_NULL(profile);
CU_ASSERT_TRUE(strchr(profile, '-') != NULL); CU_ASSERT_STRING_NOT_EQUAL(profile, "");
} }
int int
@ -105,7 +105,7 @@ main(void)
return CU_get_error(); return CU_get_error();
} }
if (! CU_add_test(config_tests, "test of init_config()", test_init_config)) { if (! CU_add_test(config_tests, "test of gl_init_config()", test_init_config)) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();
} }
@ -116,17 +116,17 @@ main(void)
return CU_get_error(); return CU_get_error();
} }
if (! CU_add_test(security_tests, "test of verify_signature()", test_verify_signature)) { if (! CU_add_test(security_tests, "test of gl_verify_signature()", test_verify_signature)) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();
} }
if (! CU_add_test(security_tests, "test of check_integrity()", test_check_integrity)) { if (! CU_add_test(security_tests, "test of gl_check_integrity()", test_check_integrity)) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();
} }
if (! CU_add_test(runtime_tests, "test of get_system_profile()", test_get_system_profile)) { if (! CU_add_test(runtime_tests, "test of gl_get_system_profile()", test_get_system_profile)) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();
} }