Version 1.08 with public source code release.

This commit is contained in:
icex2
2020-10-03 20:56:55 +02:00
parent 656148121d
commit 762bf140c0
555 changed files with 55502 additions and 3 deletions
+17
View File
@@ -0,0 +1,17 @@
#include "util/adler32.h"
#define BASE 65521
uint32_t util_adler32_calc(uint32_t initval, const uint8_t* input, size_t length)
{
unsigned int s1 = initval & 0xffff;
unsigned int s2 = (initval >> 16) & 0xffff;
unsigned int n;
for (n = 0; n < length; n++) {
s1 = (s1 + input[n]) % BASE;
s2 = (s2 + s1) % BASE;
}
return (s2 << 16) + s1;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef UTIL_ADLER32_H
#define UTIL_ADLER32_H
#include <stdint.h>
#include <stdlib.h>
/**
* Calculate the adler32 checksum
*
* @param initval Initial value for calculation
* @param input Input buffer to checksum
* @param length Length of the input buffer
* @return Adler32 value of input buffer
*/
uint32_t util_adler32_calc(uint32_t initval, const uint8_t* input, size_t length);
#endif
+55
View File
@@ -0,0 +1,55 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "util/array.h"
#include "util/log.h"
#include "util/mem.h"
void util_array_init(struct util_array* array)
{
memset(array, 0, sizeof(*array));
}
void util_array_remove_(size_t itemsz, struct util_array* array, size_t i)
{
array->nitems--;
memmove(((uint8_t *) array->items) + i * itemsz,
((uint8_t *) array->items) + (i + 1) * itemsz,
(array->nitems - i) * itemsz);
}
void* util_array_reserve_(size_t itemsz, struct util_array* array, size_t nitems)
{
size_t new_nalloced;
size_t new_nitems;
void* result;
new_nitems = array->nitems + nitems;
if (new_nitems > array->nalloced) {
new_nalloced = array->nalloced;
if (new_nalloced == 0) {
new_nalloced = 1;
}
while (new_nalloced < new_nitems) {
new_nalloced *= 2;
}
array->items = util_xrealloc(array->items, new_nalloced * itemsz);
array->nalloced = new_nalloced;
}
result = ((uint8_t *) array->items) + array->nitems * itemsz;
array->nitems = new_nitems;
return result;
}
void util_array_fini(struct util_array* array)
{
free(array->items);
}
+60
View File
@@ -0,0 +1,60 @@
#ifndef UTIL_ARRAY_H
#define UTIL_ARRAY_H
#include <stddef.h>
/**
* Array with a fixed number of items
*/
struct util_array {
void* items;
size_t nitems;
size_t nalloced;
};
#define util_array_item(type, array, i) \
(&(((type*) (array)->items)[i]))
#define util_array_reserve(type, array, nitems) \
((type*) util_array_reserve_(sizeof(type), array, nitems))
#define util_array_remove(type, array, i) \
util_array_remove_(sizeof(type), array, i)
#define util_array_append(type, array) \
util_array_reserve(type, array, 1)
/**
* Initialize the array after allocation
*
* @param array Pointer to allocated array to initialize
*/
void util_array_init(struct util_array* array);
/**
* Reserve/allocate space for the specified number of items in the array
*
* @param itemsz Size of a single item
* @param array Array to use
* @param Number of items with itemsz each to reserve
* @return Pointer to first index of reserved slots in array
*/
void* util_array_reserve_(size_t itemsz, struct util_array* array, size_t nitems);
/**
* Remove an item from the array. The array will be shrunken to current_size - 1
*
* @param itemsz Size of a single item
* @param array Array to remove the item from
* @param i Index of the item to remove
*/
void util_array_remove_(size_t itemsz, struct util_array* array, size_t i);
/**
* Free/Deallocate an allocated array
*
* @param array Allocated array to free
*/
void util_array_fini(struct util_array* array);
#endif
+170
View File
@@ -0,0 +1,170 @@
#include <ctype.h>
#include "util/base64.h"
#include "util/mem.h"
// Copy-pasted with minor tweaks from: https://github.com/littlstar/b64.c
static const char b64_table[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
uint8_t* util_base64_encode(const uint8_t* src, size_t len, size_t* out_len)
{
int i = 0;
int j = 0;
unsigned char *enc = NULL;
size_t size = 0;
unsigned char buf[4];
unsigned char tmp[3];
enc = (unsigned char *) util_xmalloc(0);
while (len--) {
tmp[i++] = *(src++);
if (3 == i) {
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
enc = (unsigned char *) util_xrealloc(enc, size + 4);
for (i = 0; i < 4; ++i) {
enc[size++] = b64_table[buf[i]];
}
i = 0;
}
}
if (i > 0) {
for (j = i; j < 3; ++j) {
tmp[j] = '\0';
}
buf[0] = (tmp[0] & 0xfc) >> 2;
buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
buf[3] = tmp[2] & 0x3f;
for (j = 0; (j < i + 1); ++j) {
enc = (unsigned char *) util_xrealloc(enc, size + 1);
enc[size++] = b64_table[buf[j]];
}
while ((i++ < 3)) {
enc = (unsigned char *) util_xrealloc(enc, size + 1);
enc[size++] = '=';
}
}
enc = (unsigned char *) util_xrealloc(enc, size + 1);
enc[size] = '\0';
*out_len = size;
return enc;
}
uint8_t* util_base64_decode(const uint8_t* src, size_t len, size_t* out_len)
{
int i = 0;
int j = 0;
int l = 0;
size_t size = 0;
unsigned char *dec = NULL;
unsigned char buf[3];
unsigned char tmp[4];
dec = (unsigned char *) util_xmalloc(0);
while (len--) {
if ('=' == src[j]) {
break;
}
if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) {
break;
}
tmp[i++] = src[j++];
if (4 == i) {
for (i = 0; i < 4; ++i) {
for (l = 0; l < 64; ++l) {
if (tmp[i] == b64_table[l]) {
tmp[i] = l;
break;
}
}
}
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
dec = (unsigned char *) util_xrealloc(dec, size + 3);
if (dec != NULL){
for (i = 0; i < 3; ++i) {
dec[size++] = buf[i];
}
} else {
return NULL;
}
i = 0;
}
}
if (i > 0) {
for (j = i; j < 4; ++j) {
tmp[j] = '\0';
}
for (j = 0; j < 4; ++j) {
for (l = 0; l < 64; ++l) {
if (tmp[j] == b64_table[l]) {
tmp[j] = l;
break;
}
}
}
buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
dec = (unsigned char *)util_xrealloc(dec, size + (i - 1));
if (dec != NULL){
for (j = 0; (j < i - 1); ++j) {
dec[size++] = buf[j];
}
} else {
return NULL;
}
}
dec = (unsigned char *)util_xrealloc(dec, size + 1);
if (dec != NULL){
dec[size] = '\0';
} else {
return NULL;
}
if (out_len != NULL) {
*out_len = size;
}
return dec;
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <stdlib.h>
#include <stdint.h>
uint8_t* util_base64_encode(const uint8_t* src, size_t len, size_t* out_len);
uint8_t* util_base64_decode(const uint8_t* src, size_t len, size_t* out_len);
+18
View File
@@ -0,0 +1,18 @@
#ifndef UTIL_DEFS_H
#define UTIL_DEFS_H
#include <stdint.h>
#include <string.h>
#define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#define XSTRINGIFY(arg) STRINGIFY(arg)
#define lengthof(x) (sizeof(x) / sizeof(x[0]))
#define containerof(ptr, outer_t, member) \
((void *) (((uint8_t *) ptr) - offsetof(outer_t, member)))
#endif
+222
View File
@@ -0,0 +1,222 @@
#define LOG_MODULE "util-fs"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "util/defs.h"
#include "util/fs.h"
#include "util/log.h"
#include "util/mem.h"
bool util_file_load(const char* filename, void** out_bytes, size_t *out_nbytes,
bool text_mode)
{
FILE *f;
void *bytes;
size_t nbytes;
int result;
log_assert(out_bytes != NULL);
*out_bytes = NULL;
f = fopen(filename, "rb");
if (f == NULL) {
log_warn("%s: Error opening file: %s", filename, strerror(errno));
goto open_fail;
}
fseek(f, 0, SEEK_END);
nbytes = ftell(f);
fseek(f, 0, SEEK_SET);
/* Add for null terminator */
if (text_mode) {
nbytes++;
}
bytes = malloc(nbytes);
if (bytes == NULL) {
log_warn("%s: malloc(%u) failed", filename, (unsigned int) nbytes);
goto malloc_fail;
}
if (text_mode) {
result = fread(bytes, nbytes - 1, 1, f);
} else {
result = fread(bytes, nbytes, 1, f);
}
if (result != 1) {
log_warn("%s: Error reading file: %s", filename, strerror(errno));
goto read_fail;
}
*out_bytes = bytes;
if (out_nbytes != NULL) {
*out_nbytes = nbytes;
}
fclose(f);
/* Add null terminator */
if (text_mode) {
((char*) bytes)[nbytes - 1] = '\0';
}
log_debug("File loaded %s, size %d", filename, *out_nbytes);
return true;
read_fail:
free(bytes);
malloc_fail:
fclose(f);
open_fail:
return false;
}
bool util_file_save(const char* filename, const void* bytes, size_t nbytes)
{
FILE *f;
int result;
f = fopen(filename, "wb");
if (f == NULL) {
log_warn("%s: Error creating file: %s", filename, strerror(errno));
goto open_fail;
}
result = fwrite(bytes, nbytes, 1, f);
if (result != 1) {
log_warn("%s: Error writing file: %s", filename, strerror(errno));
goto write_fail;
}
fclose(f);
log_debug("File saved %s, size %d", filename, nbytes);
return true;
write_fail:
fclose(f);
open_fail:
return false;
}
bool util_fs_path_exists(const char* path)
{
// Don't use stat here because that doesn't work on mounts, e.g. sqashfs/appimage
bool exists;
FILE* file = fopen(path, "r");
exists = file != NULL;
if (file != NULL) {
fclose(file);
}
return exists;
}
bool util_fs_mkdir(const char* path)
{
return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
}
bool util_fs_mkfile(const char* path)
{
FILE* file;
bool res;
file = fopen(path, "a");
res = file != NULL;
if (file) {
fclose(file);
}
return res;
}
char* util_fs_get_path_to_file(const char* path)
{
size_t len;
char* res;
len = strlen(path);
for (ssize_t i = len - 1; i >= 0; i--) {
if (path[i] == '/') {
len--;
break;
}
len--;
}
res = (char*) util_xmalloc(sizeof(char) * (len + 1));
strncpy(res, path, len);
res[len] = '\0';
return res;
}
char* util_fs_get_filename(const char* path)
{
size_t path_len;
size_t len;
char* res;
len = strlen(path);
path_len = len;
for (ssize_t i = len - 1; i >= 0; i--) {
if (path[i] == '/') {
len++;
break;
}
len--;
}
res = (char*) util_xmalloc(sizeof(char) * ((path_len - len) + 1));
strncpy(res, path + len, path_len - len);
res[path_len - len] = '\0';
return res;
}
char* util_fs_get_abs_path(const char* path)
{
char* real_path;
real_path = realpath(path, NULL);
if (!real_path) {
log_error("Resolving path '%s' to absolute path failed: %s", path,
strerror(errno));
}
return real_path;
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef UTIL_FS_H
#define UTIL_FS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
/**
* Load a file fully into memory
*
* @param filename Path of the file to load
* @param bytes Pointer to a pointer to return an allocated location with the
* loaded data to
* @param nbytes Pointer to a variable to return the read size of the file to
* @param text_mode True to read the file in text mode (add terminating \0),
* false for binary mode
* @return True on success, false on error
*/
bool util_file_load(const char* filename, void** bytes, size_t* nbytes, bool text_mode);
/**
* Save a buffer to a file (overwrite any existing files with the same name)
*
* @param filename Path to save the data to
* @param bytes Pointer to buffer with contents to save
* @param nbytes Number of bytes to write to the file
* @return True on success, false on error
*/
bool util_file_save(const char* filename, const void* bytes, size_t nbytes);
/**
* Check if a normal file, folder, symlink, ... exists
*
* @return True if exists, false otherwise
*/
bool util_fs_path_exists(const char* path);
/**
* Create a new directory
*
* @param path Path to directory
* @return True if successful, false on failure
*/
bool util_fs_mkdir(const char* path);
/**
* Create a new empty file
*
* @param path Path to the file to create
* @return True if successful, false on failure
*/
bool util_fs_mkfile(const char* path);
/**
* Get the path pointing to the file (without the filename)
*
* @param path Full path to file
* @return Newly allocated string (caller has to free) containing the path, only
*/
char* util_fs_get_path_to_file(const char* path);
/**
* Get the start position of the filename in the path
*
* @param path Full path to file
* @return Newly allocated string (caller has to free) containing the filename,
* only
*/
char* util_fs_get_filename(const char* path);
/**
* Get the absolute path of the give (relative) path
*
* @param path (Relative) path
* @return Allocated string (caller has to free) containing the full absolute
* path for the given (relative) path
*/
char* util_fs_get_abs_path(const char* path);
#endif
+10
View File
@@ -0,0 +1,10 @@
#define LOG_MODULE "util-glibc"
#include <gnu/libc-version.h>
#include "util/log.h"
void util_glibc_info_log()
{
log_info("glibc release '%s', version '%s'", gnu_get_libc_release(), gnu_get_libc_version());
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef PUMPTOOLS_UTIL_GLIBC_H
#define PUMPTOOLS_UTIL_GLIBC_H
void util_glibc_info_log();
#endif
+73
View File
@@ -0,0 +1,73 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include "util/hex.h"
#include "util/log.h"
static bool util_hex_decode_nibble(char c, uint8_t *nibble)
{
if (c >= '0' && c <= '9') {
*nibble = c - '0';
} else if (c >= 'A' && c <= 'F') {
*nibble = c - 'A' + 10;
} else if (c >= 'a' && c <= 'f') {
*nibble = c - 'a' + 10;
} else {
return false;
}
return true;
}
bool util_hex_decode(void *ptr, size_t nbytes, const char *chars, size_t nchars)
{
uint8_t *bytes = ptr;
uint32_t i;
uint8_t hi;
uint8_t lo;
log_assert(nchars >= 2 * nbytes);
for (i = 0 ; i < nbytes ; i++) {
if ( !util_hex_decode_nibble(chars[2 * i + 0], &hi) ||
!util_hex_decode_nibble(chars[2 * i + 1], &lo)) {
return false;
}
bytes[i] = (hi << 4) | lo;
}
return true;
}
static void util_hex_encode(const void *ptr, size_t nbytes, char *chars,
size_t nchars, const char *digits)
{
const uint8_t *bytes = ptr;
size_t i;
log_assert(nchars >= 2 * nbytes + 1);
for (i = 0 ; i < nbytes ; i++) {
chars[i * 2 + 0] = digits[bytes[i] >> 4];
chars[i * 2 + 1] = digits[bytes[i] & 15];
}
chars[nbytes * 2] = '\0';
}
void util_hex_encode_lc(const void *bytes, size_t nbytes, char *chars,
size_t nchars)
{
util_hex_encode(bytes, nbytes, chars, nchars, "0123456789abcdef");
}
void util_hex_encode_uc(const void *bytes, size_t nbytes, char *chars,
size_t nchars)
{
util_hex_encode(bytes, nbytes, chars, nchars, "0123456789ABCDEF");
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef UTIL_HEX_H
#define UTIL_HEX_H
#include <stdbool.h>
#include <stddef.h>
bool util_hex_decode(void *bytes, size_t nbytes, const char *chars,
size_t nchars);
void util_hex_encode_uc(const void *bytes, size_t nbytes, char *chars,
size_t nchars);
void util_hex_encode_lc(const void *bytes, size_t nbytes, char *chars,
size_t nchars);
#endif
+22
View File
@@ -0,0 +1,22 @@
#include "util/iobuf.h"
#include <string.h>
size_t util_iobuf_move(struct util_iobuf* dest, struct util_const_iobuf* src)
{
size_t dest_avail;
size_t src_avail;
size_t chunksz;
dest_avail = dest->nbytes - dest->pos;
src_avail = src->nbytes - src->pos;
chunksz = dest_avail < src_avail ? dest_avail : src_avail;
memcpy(&dest->bytes[dest->pos], &src->bytes[src->pos], chunksz);
dest->pos += chunksz;
src->pos += chunksz;
return chunksz;
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef UTIL_IOBUF_H
#define UTIL_IOBUF_H
#include <stddef.h>
#include <stdint.h>
/**
* Iobuffer struct holding data, size and position
*/
struct util_iobuf {
uint8_t* bytes;
size_t nbytes;
size_t pos;
};
/**
* Const variant of iobuffer struct holding data, size and position
*/
struct util_const_iobuf {
const uint8_t* bytes;
size_t nbytes;
size_t pos;
};
/**
* Move the contents of one iobuffer to another one (data, size and pos)
*
* @param dest Destination to move to
* @param src Source to move from
* @return Number of bytes moved (this can be less than the source's size
* e.g. if destination size < src size)
*/
size_t util_iobuf_move(struct util_iobuf* dest, struct util_const_iobuf* src);
#endif
+91
View File
@@ -0,0 +1,91 @@
#include "util/list.h"
#include <stddef.h>
#include <string.h>
void util_list_init(struct util_list* list)
{
memset(list, 0, sizeof(*list));
}
void util_list_append(struct util_list* list, struct util_list_node* node)
{
node->next = NULL;
if (list->tail != NULL) {
list->tail->next = node;
} else {
list->head = node;
}
list->tail = node;
}
bool util_list_contains(struct util_list* list, struct util_list_node* node)
{
struct util_list_node* pos;
for (pos = list->head ; pos != NULL ; pos = pos->next) {
if (pos == node) {
return true;
}
}
return false;
}
struct util_list_node* util_list_pop_head(struct util_list* list)
{
struct util_list_node* node;
if (list->head == NULL) {
return NULL;
}
node = list->head;
list->head = node->next;
if (node->next == NULL) {
list->tail = NULL;
}
node->next = NULL;
return node;
}
void util_list_remove(struct util_list* list, struct util_list_node* node)
{
struct util_list_node* pos;
struct util_list_node* prev;
for (prev = NULL, pos = list->head
; pos != NULL
; prev = pos, pos = pos->next) {
if (pos == node) {
if (prev != NULL) {
prev->next = node->next;
} else {
list->head = node->next;
}
if (node->next == NULL) {
list->tail = prev;
}
node->next = NULL;
return;
}
}
}
bool util_list_empty(struct util_list* list)
{
return list->head == NULL;
}
inline struct util_list_node* util_list_peek_head(struct util_list* list)
{
return list->head;
}
+79
View File
@@ -0,0 +1,79 @@
#ifndef UTIL_LIST_H
#define UTIL_LIST_H
#include <stdbool.h>
#include <stddef.h>
/**
* (Doubly linked) list object
*/
struct util_list {
struct util_list_node* head;
struct util_list_node* tail;
};
/**
* List element/node
*/
struct util_list_node {
struct util_list_node* next;
};
/**
* Initialize an allocated list
*
* @param list Pointer to a list to initialize
*/
void util_list_init(struct util_list* list);
/**
* Append an element to a list
*
* @param list List to append to
* @param node Node to append to the list
*/
void util_list_append(struct util_list* list, struct util_list_node* node);
/**
* Check if the list contains the specified element
*
* @param list List to check
* @param node Node to look for in the list
* @return True if list contains the specified node, false otherwise
*/
bool util_list_contains(struct util_list* list, struct util_list_node* node);
/**
* Peak (get but do not remove) the head of the list
*
* @param list List to peak
* @return Head element of the list (or null if empty)
*/
struct util_list_node* util_list_peek_head(struct util_list* list);
/**
* Pop (get and remove) the head of the list
*
* @param list List to pop
* @return Removed head element of the list (or null if empty)
*/
struct util_list_node* util_list_pop_head(struct util_list* list);
/**
* Remove a specific element of the list. If the element is not part of the,
* the list is not modified.
*
* @param list List to remove an element from
* @param node Element to remove from the list
*/
void util_list_remove(struct util_list* list, struct util_list_node* node);
/**
* Check if a list is empty
*
* @param list List to check
* @return True if empty, false otherwise
*/
bool util_list_empty(struct util_list* list);
#endif
+149
View File
@@ -0,0 +1,149 @@
#define LOG_MODULE "util-log"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "util/defs.h"
#include "util/log.h"
#include "util/str.h"
#include "util/time.h"
#define COLORIZING_CONTROL_SEQ "\033[%d;%dm%s\033[0m"
static void util_log_format(enum util_log_level level, const char* module,
const char* trace_file, size_t trace_line, const char* fmt, va_list ap);
static void util_log_writer_console(void* ctx, enum util_log_level level, const char* module, const char* trace_file,
size_t trace_line, const char* msg);
static void util_log_writer_file(void* ctx, enum util_log_level level, const char* module, const char* trace_file,
size_t trace_line, const char* msg);
static const char util_log_level_chars[] = "DEWIM";
static enum util_log_level util_log_level = LOG_LEVEL_DEBUG;
static FILE* util_log_file;
void util_log_set_file(const char* path, bool append)
{
const char* mode = append ? "a+" : "w+";
if (path) {
util_log_file = fopen(path, mode);
log_info("Open log file: %s", path);
}
}
void util_log_set_level(enum util_log_level new_level)
{
util_log_level = new_level;
}
FILE* util_log_get_file_handle(void)
{
return util_log_file;
}
void util_log(enum util_log_level level, const char* module, const char* trace_file, size_t trace_line,
const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
util_log_format(level, module, trace_file, trace_line, fmt, ap);
va_end(ap);
}
static void util_log_colorize_text(enum util_log_level level, const char* text, char* buffer)
{
switch (level) {
case LOG_LEVEL_DEBUG:
sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 37, text);
break;
case LOG_LEVEL_INFO:
sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 34, text);
break;
case LOG_LEVEL_WARN:
sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 33, text);
break;
case LOG_LEVEL_ERROR:
sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 31, text);
break;
case LOG_LEVEL_DIE:
sprintf(buffer, COLORIZING_CONTROL_SEQ, 0, 31, text);
break;
default:
log_die_illegal_state();
break;
}
}
static void util_log_format(enum util_log_level level, const char* module,
const char* trace_file, size_t trace_line, const char* fmt, va_list ap)
{
char msg[8192];
if (level <= util_log_level) {
util_str_vformat(msg, sizeof(msg), fmt, ap);
util_log_writer_console(NULL, level, module, trace_file, trace_line, msg);
if (util_log_file != NULL) {
util_log_writer_file(util_log_file, level, module, trace_file, trace_line, msg);
}
}
if (level == LOG_LEVEL_DIE) {
abort();
}
}
static void util_log_writer_console(void* ctx, enum util_log_level level, const char* module, const char* trace_file,
size_t trace_line, const char* msg)
{
char text_level[128];
char text_level_color[128];
util_str_format(text_level, sizeof(text_level), "[%c]", util_log_level_chars[level]);
util_log_colorize_text(level, text_level, text_level_color);
// ---------------------------
struct util_time_timestamp timestamp;
util_time_get_current_time(&timestamp);
// ---------------------------
char line[8192];
util_str_format(line, sizeof(line), "%s[%d/%d/%d-%d:%d:%d:%d][%s][%s:%d] %s\n", text_level_color, timestamp.year,
timestamp.month, timestamp.day, timestamp.hour, timestamp.min, timestamp.sec, timestamp.millisec,
module, trace_file, trace_line, msg);
printf("%s", line);
}
static void util_log_writer_file(void* ctx, enum util_log_level level, const char* module, const char* trace_file,
size_t trace_line, const char* msg)
{
struct util_time_timestamp timestamp;
util_time_get_current_time(&timestamp);
// ---------------------------
char line[8192];
size_t line_len;
line_len = util_str_format(line, sizeof(line), "[%c][%d/%d/%d-%d:%d:%d:%d][%s][%s:%d] %s\n",
util_log_level_chars[level], timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.min,
timestamp.sec, timestamp.millisec, module, trace_file, trace_line, msg);
fwrite(line, 1, line_len, (FILE*) ctx);
fflush((FILE*) ctx);
}
+97
View File
@@ -0,0 +1,97 @@
#ifndef UTIL_LOG_H
#define UTIL_LOG_H
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "util/defs.h"
#ifndef LOG_MODULE
#define LOG_MODULE FILENAME
#endif
#ifndef LOG_SUPPRESS
/* Don't expose source file names and absolute paths on public releases */
#ifdef PT_PUBLIC_RELEASE
#undef FILENAME
#define FILENAME ""
#define SOURCE_LINE 0
#else
#define SOURCE_LINE __LINE__
#endif
#define log_debug(...) util_log(LOG_LEVEL_DEBUG, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__)
#define log_info(...) util_log(LOG_LEVEL_INFO, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__)
#define log_warn(...) util_log(LOG_LEVEL_WARN, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__)
#define log_error(...) util_log(LOG_LEVEL_ERROR, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__)
#define log_die(...) util_log(LOG_LEVEL_DIE, LOG_MODULE, FILENAME, SOURCE_LINE, __VA_ARGS__)
#define log_die_illegal_state() util_log(LOG_LEVEL_DIE, LOG_MODULE, FILENAME, SOURCE_LINE, "Illegal state")
#else
#define log_debug(...)
#define log_info(...)
#define log_warn(...)
#define log_error(...)
#define log_die(...)
#endif
#define log_assert(x) \
do { \
if (!(x)) { \
log_die(FILENAME, __LINE__, __FUNCTION__); \
} \
} while (0)
/**
* Different log levels for logging
*/
enum util_log_level {
LOG_LEVEL_DIE = 0,
LOG_LEVEL_ERROR = 1,
LOG_LEVEL_WARN = 2,
LOG_LEVEL_INFO = 3,
LOG_LEVEL_DEBUG = 4
};
/**
* Open a log file to write log output to in addition to stdout
*
* @param path Path of the log file (existing files are overwritten of append argument false)
* @param append True to append to an existing file, false to create a new file with the specified name
*/
void util_log_set_file(const char* path, bool append);
/**
* Set the log level for logging
*
* @param new_level New log level
*/
void util_log_set_level(enum util_log_level new_level);
/**
* Get the log file handle (required for hooking to filter it on fwrite calls on the filehook monitor)
*
* @return FILE handle of log file or NULL if logging to file disabled
*/
FILE* util_log_get_file_handle(void);
/**
* Log a message
*
* Don't use this call to log something, use the macros instead
*
* @param level Log level of the message
* @param module Name of the module where this function is called
* @param trace_file Additional trace information, file name
* @param trace_line Additional trace information, line number
* @param fmt Format string of log message
* @param ... Arguments for format string
*/
void util_log(enum util_log_level level, const char* module, const char* trace_file, size_t trace_line,
const char* fmt, ...);
#endif
+108
View File
@@ -0,0 +1,108 @@
#define LOG_MODULE "util-mem"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "util/log.h"
#include "util/mem.h"
static bool _util_mem_debug_output;
static void* _util_xmalloc(size_t nbytes);
static void* _util_xrealloc(void* mem, size_t nbytes);
static void _util_xfree(void** mem);
static const struct util_mem_interface _util_mem_interface_default = {
.xmalloc = _util_xmalloc,
.xrealloc = _util_xrealloc,
.xfree = _util_xfree,
};
static const struct util_mem_interface* _util_mem_interface = &_util_mem_interface_default;
static void* _util_xmalloc(size_t nbytes)
{
void* mem;
mem = malloc(nbytes);
if (_util_mem_debug_output) {
log_debug("xmalloc(%d): %p", nbytes, mem);
}
if (mem == NULL) {
log_die("xmalloc(%u) failed", (uint32_t) nbytes);
return NULL;
}
return mem;
}
static void* _util_xrealloc(void* mem, size_t nbytes)
{
void* newmem;
newmem = realloc(mem, nbytes);
if (_util_mem_debug_output) {
log_debug("xrealloc(%p %d): %p", mem, nbytes, newmem);
}
if (newmem == NULL) {
log_die("xrealloc(%p, %u) failed", mem, (uint32_t) nbytes);
return NULL;
}
return newmem;
}
static void _util_xfree(void** mem)
{
log_assert(mem);
if (*mem != NULL) {
if (_util_mem_debug_output) {
log_debug("xfree(%p %p)", mem, *mem);
}
free(*mem);
*mem = NULL;
} else {
if (_util_mem_debug_output) {
log_warn("xfree(%p NULL)", mem);
}
}
}
void util_mem_init(const struct util_mem_interface* interface)
{
log_assert(interface);
_util_mem_interface = interface;
}
void util_mem_init_default()
{
_util_mem_interface = &_util_mem_interface_default;
}
void util_mem_enable_debug_output()
{
_util_mem_debug_output = true;
}
void* util_xmalloc(size_t nbytes)
{
return _util_mem_interface->xmalloc(nbytes);
}
void* util_xrealloc(void* mem, size_t nbytes)
{
return _util_mem_interface->xrealloc(mem, nbytes);
}
void util_xfree(void** mem)
{
_util_mem_interface->xfree(mem);
}
+57
View File
@@ -0,0 +1,57 @@
#ifndef UTIL_MEM_H
#define UTIL_MEM_H
#include <stddef.h>
#include <stdbool.h>
typedef void* (*util_xmalloc_t)(size_t nbytes);
typedef void* (*util_xrealloc_t)(void* mem, size_t nbytes);
typedef void (*util_free_t)(void** mem);
struct util_mem_interface {
util_xmalloc_t xmalloc;
util_xrealloc_t xrealloc;
util_free_t xfree;
};
/**
* Install a different memory interfacee, e.g. to use a different allocator or hooks for unit-testing.
*/
void util_mem_init(const struct util_mem_interface* interface);
/**
* Optional, initialize the default memory interface. This needs to be called only if you want to switch back from
* a non-default interface that got installed using util_mem_init.
*/
void util_mem_init_default();
/**
* Enable debug output of all allocations and de-allocations that go through the default interface of this module.
*/
void util_mem_enable_debug_output();
/**
* Allocate memory on the heap (malloc wrapper)
*
* @param nbytes Number of bytes to allocate
* @return Pointer to allocated memory
*/
void* util_xmalloc(size_t nbytes);
/**
* Realloc memory (realloc wrapper)
*
* @param mem Pointer to allocated memory to realloc/expand
* @param nbytes New size of memory region
* @return Pointer to reallocated memory region
*/
void* util_xrealloc(void* mem, size_t nbytes);
/**
* Free allocated memory.
*
* @param mem Pointer to the pointer with allocated memory to free. The pointer to the memory will be set to NULL.
*/
void util_xfree(void** mem);
#endif
+41
View File
@@ -0,0 +1,41 @@
#include <stdlib.h>
#include <string.h>
#include "util/net.h"
#include "util/str.h"
bool util_net_split_ipv4_str(const char* str, char** address, uint16_t* port)
{
char* tmp = util_str_dup(str);
char* pch = strtok(tmp, ":");
int counter = 0;
*address = NULL;
*port = 0xFFFF;
while (pch != NULL) {
switch (counter) {
case 0:
*address = util_str_dup(pch);
break;
case 1:
*port = (uint16_t) strtol(pch, NULL, 10);
break;
default:
if (*address) {
free(*address);
}
free(tmp);
return false;
}
pch = strtok (NULL, ":");
counter++;
}
free(tmp);
return true;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef UTIL_NET_H
#define UTIL_NET_H
#include <stdbool.h>
#include <stdint.h>
/**
* Split an ipv4 string (e.g. 127.0.0.1:22 or just 127.0.0.1) into address and port
*
* @param str String to split
* @param address Address part (must be free'd by caller)
* @param port Port part (or -1 if it doesn't exist)
* @return True if successful, false on format error
*/
bool util_net_split_ipv4_str(const char* str, char** address, uint16_t* port);
#endif
+758
View File
@@ -0,0 +1,758 @@
#define LOG_MODULE "util-options"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util/defs.h"
#include "util/fs.h"
#include "util/hex.h"
#include "util/log.h"
#include "util/mem.h"
#include "util/options.h"
#include "util/str.h"
static struct util_options_opts* util_options_get2(int argc, char** argv,
const struct util_options_defs* option_defs);
static bool util_options_init_from_args(struct util_options_opts* options,
const struct util_options_defs* option_defs, int argc, char** argv);
static bool util_options_init_from_file(struct util_options_opts* options,
const struct util_options_defs* option_defs, char* file_path);
static bool util_options_write_default_options_file(
const struct util_options_defs* option_defs, char* file_path);
static int util_options_argc;
static char** util_options_argv;
void util_options_init(int argc, char** argv)
{
util_options_argc = argc;
util_options_argv = argv;
}
struct util_options_opts* util_options_get(
const struct util_options_defs* option_defs)
{
struct util_options_opts* options;
options = util_options_get2(util_options_argc, util_options_argv,
option_defs);
if (!options) {
exit(0);
}
return options;
}
int util_options_get_int(const struct util_options_opts* opts,
const char* name)
{
for (uint32_t i = 0; i < opts->entries; i++) {
if (!strcmp(opts->defs->defs[i].name, name)) {
if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_INT) {
log_warn("Option %s is not of type int", name);
return 0;
}
if (opts->values[i].avail) {
return opts->values[i].value.i;
} else {
return opts->defs->defs[i].default_value.i;
}
}
}
log_warn("Could not find int option %s", name);
return 0;
}
double util_options_get_double(const struct util_options_opts* opts, const char* name)
{
for (uint32_t i = 0; i < opts->entries; i++) {
if (!strcmp(opts->defs->defs[i].name, name)) {
if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_DOUBLE) {
log_warn("Option %s is not of type double", name);
return 0;
}
if (opts->values[i].avail) {
return opts->values[i].value.d;
} else {
return opts->defs->defs[i].default_value.d;
}
}
}
log_warn("Could not find double option %s", name);
return 0;
}
const char* util_options_get_str(const struct util_options_opts* opts,
const char* name)
{
for (uint32_t i = 0; i < opts->entries; i++) {
if (!strcmp(opts->defs->defs[i].name, name)) {
if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_STR) {
log_warn("Option %s is not of type str", name);
return 0;
}
if (opts->values[i].avail) {
return opts->values[i].value.str;
} else {
return opts->defs->defs[i].default_value.str;
}
}
}
log_warn("Could not find str option %s", name);
return NULL;
}
bool util_options_get_bool(const struct util_options_opts* opts,
const char* name)
{
for (uint32_t i = 0; i < opts->entries; i++) {
if (!strcmp(opts->defs->defs[i].name, name)) {
if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_BOOL) {
log_warn("Option %s is not of type bool", name);
return false;
}
if (opts->values[i].avail) {
return opts->values[i].value.b;
} else {
return opts->defs->defs[i].default_value.b;
}
}
}
log_warn("Could not find bool option %s", name);
return false;
}
const uint8_t* util_options_get_bin(const struct util_options_opts* opts,
const char* name, size_t* length)
{
for (uint32_t i = 0; i < opts->entries; i++) {
if (!strcmp(opts->defs->defs[i].name, name)) {
if (opts->defs->defs[i].type != UTIL_OPTIONS_TYPE_BIN) {
log_warn("Option %s is not of type bin", name);
return 0;
}
if (opts->values[i].avail) {
if (length) {
*length = opts->values[i].value.bin.len;
}
return opts->values[i].value.bin.data;
} else {
if (length) {
*length = opts->defs->defs[i].default_value.bin.len;
}
return opts->defs->defs[i].default_value.bin.data;
}
}
}
log_warn("Could not find bin option %s", name);
return NULL;
}
void util_options_print_usage(const struct util_options_defs* option_defs)
{
printf(
"%s\nSpecify options as arguments or use --options [path file] to "
"specify a config file containing key=value per line entries\n",
option_defs->usage_header);
for (uint32_t i = 0; i < option_defs->ndefs; i++) {
switch (option_defs->defs[i].type) {
case UTIL_OPTIONS_TYPE_INT:
{
printf(
" -%c [int] %s: %s\n"
" default: %d\n",
option_defs->defs[i].param, option_defs->defs[i].name,
option_defs->defs[i].description,
option_defs->defs[i].default_value.i);
break;
}
case UTIL_OPTIONS_TYPE_DOUBLE:
{
printf(
" -%c [double] %s: %s\n"
" default: %f\n",
option_defs->defs[i].param, option_defs->defs[i].name,
option_defs->defs[i].description,
option_defs->defs[i].default_value.d);
break;
}
case UTIL_OPTIONS_TYPE_STR:
{
printf(
" -%c [str] %s: %s\n"
" default: %s\n",
option_defs->defs[i].param, option_defs->defs[i].name,
option_defs->defs[i].description,
option_defs->defs[i].default_value.str);
break;
}
case UTIL_OPTIONS_TYPE_BOOL:
{
printf(
" -%c [bool] %s: %s\n"
" default: %d\n",
option_defs->defs[i].param, option_defs->defs[i].name,
option_defs->defs[i].description,
option_defs->defs[i].default_value.b);
break;
}
case UTIL_OPTIONS_TYPE_BIN:
{
size_t len = option_defs->defs[i].default_value.bin.len * 2 + 1;
char* buf = util_xmalloc(len);
util_hex_encode_uc(option_defs->defs[i].default_value.bin.data,
option_defs->defs[i].default_value.bin.len, buf, len);
printf(
" -%c [bin] %s: %s\n"
" default (len %Iu): %s\n",
option_defs->defs[i].param, option_defs->defs[i].name,
option_defs->defs[i].description,
option_defs->defs[i].default_value.bin.len,
buf);
free(buf);
break;
}
default:
{
printf(
" -%c [unkn] %s: %s\n"
" default: -invalid-\n",
option_defs->defs[i].param, option_defs->defs[i].name,
option_defs->defs[i].description);
break;
}
}
}
}
void util_options_free(struct util_options_opts* opts)
{
for (uint32_t i = 0; i < opts->entries; i++) {
switch (opts->defs->defs[i].type) {
case UTIL_OPTIONS_TYPE_STR:
{
if (opts->values[i].value.str) {
free(opts->values[i].value.str);
}
break;
}
case UTIL_OPTIONS_TYPE_BIN:
{
if (opts->values[i].value.bin.data) {
free(opts->values[i].value.bin.data);
}
break;
}
default:
break;
}
}
free(opts->values);
free(opts);
}
// if NULL, usage is printed
static struct util_options_opts* util_options_get2(
int argc, char** argv, const struct util_options_defs* option_defs)
{
bool success;
char* options_file = NULL;
struct util_options_opts* options =
(struct util_options_opts*)
util_xmalloc(sizeof(struct util_options_opts));
if (option_defs == NULL) {
options->defs = NULL;
options->values = NULL;
options->entries = 0;
return options;
}
options->defs = option_defs;
options->entries = option_defs->ndefs;
options->values = (struct util_options_value*) util_xmalloc(
sizeof(struct util_options_value) * options->entries);
memset(options->values, 0,
sizeof(struct util_options_value) * options->entries);
/* detect if we read options from a file */
for (int i = 0; i < argc; i++) {
if (!strcmp(argv[i], "--options")) {
if (i + 1 >= argc) {
log_warn("Missing argument for --options\n");
util_options_print_usage(option_defs);
util_options_free(options);
return NULL;
}
options_file = argv[i + 1];
break;
}
}
if (options_file) {
log_debug("Processing options file %s", options_file);
success = util_options_init_from_file(options, option_defs,
options_file);
if (!success) {
exit(0);
}
}
log_debug("Processing cmd args");
success = util_options_init_from_args(options, option_defs, argc, argv);
if (!success) {
util_options_print_usage(option_defs);
util_options_free(options);
return NULL;
} else {
return options;
}
}
static bool util_options_init_from_args(struct util_options_opts* options,
const struct util_options_defs* option_defs, int argc, char** argv)
{
for (int i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
continue;
}
for (uint32_t j = 0; j < options->entries; j++) {
/* prints usage */
if (argv[i][1] == option_defs->usage_param) {
return false;
}
if (options->defs->defs[j].param == argv[i][1]) {
switch (options->defs->defs[j].type) {
case UTIL_OPTIONS_TYPE_INT:
{
if (i + 1 >= argc) {
break;
}
++i;
options->values[j].value.i = atoi(argv[i]);
break;
}
case UTIL_OPTIONS_TYPE_DOUBLE:
{
if (i + 1 >= argc) {
break;
}
++i;
options->values[j].value.d = atof(argv[i]);
break;
}
case UTIL_OPTIONS_TYPE_STR:
{
if (i + 1 >= argc) {
break;
}
++i;
/* FIXME memory leak if overriding string from options
file */
if (strlen(argv[i]) > 0) {
options->values[j].value.str = util_str_dup(argv[i]);
} else {
options->values[j].value.str = NULL;
}
break;
}
case UTIL_OPTIONS_TYPE_BOOL:
{
options->values[j].value.b = true;
break;
}
case UTIL_OPTIONS_TYPE_BIN:
{
if (i + 1 >= argc) {
break;
}
++i;
/* FIXME memory leak if overriding bin data from options
file */
if (strlen(argv[i]) > 0) {
size_t len = strlen(argv[i]);
len = len / 2 + len % 2;
options->values[j].value.bin.len = len;
options->values[j].value.bin.data = util_xmalloc(len);
if (!util_hex_decode(options->values[j].value.bin.data,
options->values[j].value.bin.len, argv[i],
strlen(argv[i]))) {
log_warn("Decoding binary data for key %s "
"failed", options->defs->defs[j].name);
options->values[j].value.bin.len = 0;
options->values[j].value.bin.data = NULL;
}
} else {
options->values[j].value.bin.len = 0;
options->values[j].value.bin.data = NULL;
}
break;
}
default:
continue;
}
log_debug("Cmd arg: -%c %s (type %d): %s",
options->defs->defs[j].param, options->defs->defs[j].name,
options->defs->defs[j].type, argv[i]);
options->values[j].avail = true;
break;
}
}
}
return true;
}
static bool util_options_init_from_file(struct util_options_opts* options,
const struct util_options_defs* option_defs, char* file_path)
{
char* pos_lines;
char* pos_key_val;
char* ctx_lines;
char* ctx_key_val;
char* data;
size_t len;
if (!util_file_load(file_path, (void**) &data, &len, true)) {
/* If file does not exist, create one with default configuration
values */
if (util_fs_path_exists(file_path)) {
log_warn("Loading options file %s failed, faulty or corrupted "
"configuration", file_path);
} else {
/* Create a default config file if the usage param is set. This
indicates that we are currently not on the inject process
but already on the inject library. We want all config params
of the inject lib */
if (option_defs->usage_param) {
log_info("Options file %s does not exist, creating default...",
file_path);
if (!util_options_write_default_options_file(option_defs,
file_path)) {
log_warn("Creating default options file %s failed",
file_path);
} else {
log_info("Options file %s created. Tweak it to your needs and restart the game.",
file_path);
}
}
}
return false;
}
pos_lines = strtok_r(data, "\n", &ctx_lines);
while (pos_lines != NULL) {
char* pos_line_dup;
char* key = NULL;
char* val = NULL;
/* ignore comments and empty lines */
if (strlen(pos_lines) > 0 && pos_lines[0] != '#') {
pos_line_dup = util_str_dup(pos_lines);
pos_key_val = strtok_r(pos_line_dup, "=", &ctx_key_val);
log_debug("Line: %s", pos_lines);
if (pos_key_val != NULL) {
key = pos_key_val;
val = &pos_key_val[strlen(key) + 1];
} else {
log_warn("Invalid options line %s in options file %s", pos_lines, file_path);
free(pos_line_dup);
free(data);
return false;
}
log_debug("Key: %s, Value: %s", key, val);
/* search for key */
for (uint32_t j = 0; j < options->entries; j++) {
if (!strcmp(options->defs->defs[j].name, key)) {
switch (options->defs->defs[j].type) {
case UTIL_OPTIONS_TYPE_INT:
{
if (val) {
options->values[j].value.i = atoi(val);
} else {
options->values[j].value.i = 0;
}
break;
}
case UTIL_OPTIONS_TYPE_DOUBLE:
{
if (val) {
options->values[j].value.d = atof(val);
} else {
options->values[j].value.d = 0.0;
}
break;
}
case UTIL_OPTIONS_TYPE_STR:
{
if (val && strlen(val) > 0) {
options->values[j].value.str =
util_str_dup(val);
} else {
options->values[j].value.str = NULL;
}
break;
}
case UTIL_OPTIONS_TYPE_BOOL:
{
if (val) {
if (atoi(val) <= 0) {
options->values[j].value.b = false;
} else {
options->values[j].value.b = true;
}
} else {
options->values[j].value.b = false;
}
break;
}
case UTIL_OPTIONS_TYPE_BIN:
{
if (val && strlen(val) > 0) {
size_t lenBin = strlen(val);
lenBin = lenBin / 2 + lenBin % 2;
options->values[j].value.bin.len = lenBin;
options->values[j].value.bin.data =
util_xmalloc(lenBin);
if (!util_hex_decode(
options->values[j].value.bin.data,
options->values[j].value.bin.len, val,
strlen(val))) {
log_warn("Decoding binary data for key "
"%s failed",
options->defs->defs[j].name);
options->values[j].value.bin.len = 0;
options->values[j].value.bin.data = NULL;
}
} else {
options->values[j].value.bin.len = 0;
options->values[j].value.bin.data = NULL;
}
break;
}
default:
continue;
}
log_debug("Options file param: -%c %s (type %d): %s",
options->defs->defs[j].param,
options->defs->defs[j].name,
options->defs->defs[j].type, val ? val : "NULL");
options->values[j].avail = true;
break;
}
}
free(pos_line_dup);
}
pos_lines = strtok_r(NULL, "\n", &ctx_lines);
}
free(data);
return true;
}
static bool util_options_write_default_options_file(
const struct util_options_defs* option_defs, char* file_path)
{
FILE* file;
file = fopen(file_path, "wb");
if (file == NULL) {
return false;
}
for (uint32_t i = 0; i < option_defs->ndefs; i++) {
switch (option_defs->defs[i].type) {
case UTIL_OPTIONS_TYPE_INT:
{
fprintf(file, "# [int]: %s\n",
option_defs->defs[i].description);
fprintf(file, "%s=%d\n\n", option_defs->defs[i].name,
option_defs->defs[i].default_value.i);
break;
}
case UTIL_OPTIONS_TYPE_DOUBLE:
{
fprintf(file, "# [double]: %s\n",
option_defs->defs[i].description);
fprintf(file, "%s=%f\n\n", option_defs->defs[i].name,
option_defs->defs[i].default_value.d);
break;
}
case UTIL_OPTIONS_TYPE_STR:
{
fprintf(file, "# [str]: %s\n",
option_defs->defs[i].description);
if (option_defs->defs[i].default_value.str) {
fprintf(file, "%s=%s\n\n", option_defs->defs[i].name,
option_defs->defs[i].default_value.str);
} else {
fprintf(file, "%s=\n\n", option_defs->defs[i].name);
}
break;
}
case UTIL_OPTIONS_TYPE_BOOL:
{
fprintf(file, "# [bool (0/1)]: %s\n",
option_defs->defs[i].description);
fprintf(file, "%s=%d\n\n", option_defs->defs[i].name,
option_defs->defs[i].default_value.b);
break;
}
case UTIL_OPTIONS_TYPE_BIN:
{
fprintf(file, "# [bin]: %s\n",
option_defs->defs[i].description);
if (option_defs->defs[i].default_value.bin.data) {
size_t len =
option_defs->defs[i].default_value.bin.len * 2 + 1;
char* buf = util_xmalloc(len);
util_hex_encode_uc(
option_defs->defs[i].default_value.bin.data,
option_defs->defs[i].default_value.bin.len, buf, len);
fprintf(file, "%s=%s\n\n", option_defs->defs[i].name, buf);
free(buf);
}
break;
}
default:
{
log_warn("Invalid value type %d found",
option_defs->defs[i].type);
break;
}
}
}
fclose(file);
return true;
}
+170
View File
@@ -0,0 +1,170 @@
#ifndef UTIL_OPTIONS_H
#define UTIL_OPTIONS_H
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/**
* Value types support by option values
*/
enum util_options_type {
UTIL_OPTIONS_TYPE_INT,
UTIL_OPTIONS_TYPE_DOUBLE,
UTIL_OPTIONS_TYPE_STR,
UTIL_OPTIONS_TYPE_BOOL,
UTIL_OPTIONS_TYPE_BIN,
};
/**
* Single option definition element. Use this to define possible option
* key-value tuples to parse from an argument list
*/
struct util_options_def {
const char* name;
const char* description;
const char param;
enum util_options_type type;
union {
int i;
double d;
const char* str;
bool b;
struct {
const uint8_t* data;
size_t len;
} bin;
} default_value;
};
/**
* Option definitions. A list of key-value elements defining option values
* as well as usage information for the application
*/
struct util_options_defs {
const char* usage_header;
char usage_param;
const struct util_options_def* defs;
uint32_t ndefs;
};
/**
* A single option value as part of the key-value tuple
*/
struct util_options_value {
bool avail;
union {
int i;
double d;
char* str;
bool b;
struct {
uint8_t* data;
size_t len;
} bin;
} value;
};
/**
* Parsed option values based on an options definition
*/
struct util_options_opts {
const struct util_options_defs* defs;
struct util_options_value* values;
uint32_t entries;
};
/**
* Initialize the options module by passing the arguments from main on
*
* Make sure to call this as early as possible when entering main and before
* any other calls of this module are invoked
*
* @param argc Argc from main
* @param argv Argv from main
*/
void util_options_init(int argc, char** argv);
/**
* Get options from the initial argument list
*
* @param option_defs A list of option definitions. The arguments are parsed
* using this list. If NULL, usage information with the definition
* is printed and this call also returns NULL.
* @return A list of parsed options based on the specified definitions or
* NULL if usage information was printed.
*/
struct util_options_opts* util_options_get(
const struct util_options_defs* option_defs);
/**
* Get an integer value from an options list
*
* @param opts Parsed options list received from util_options_get
* @param name Name of the options key
* @return Value of the options key converted to an integer value. If the type
* of the options key is not matching, 0 is returned
*/
int util_options_get_int(const struct util_options_opts* opts,
const char* name);
/**
* Get a double value from an options list
*
* @param opts Parsed options list received from util_options_get
* @param name Name of the options key
* @return Value of the options key converted to a double value. If the type
* of the options key is not matching, 0 is returned
*/
double util_options_get_double(const struct util_options_opts* opts, const char* name);
/**
* Get a string from an options list
*
* @param opts Parsed options list received from util_options_get
* @param name Name of the options key
* @return Value of the options key converted to a string. If the type
* of the options key is not matching, NULL is returned
*/
const char* util_options_get_str(const struct util_options_opts* opts,
const char* name);
/**
* Get a bool value from an options list
*
* @param opts Parsed options list received from util_options_get
* @param name Name of the options key
* @return Value of the options key converted to a bool value. If the type
* of the options key is not matching, false is returned
*/
bool util_options_get_bool(const struct util_options_opts* opts,
const char* name);
/**
* Get binary data from an options list
*
* @param opts Parsed options list received from util_options_get
* @param name Name of the options key
* @param length Pointer to return the length of the binary data to
* (set to NULL if not required)
* @return Value of the options key converted to a binary array. If the type
* of the options key is not matching, NULL is returned
*/
const uint8_t* util_options_get_bin(const struct util_options_opts* opts,
const char* name, size_t* length);
/**
* Print usage information
*
* @param option_defs A list of option definitions.
*/
void util_options_print_usage(const struct util_options_defs* opts);
/**
* Free an options list
*
* @param opts Options list to free
*/
void util_options_free(struct util_options_opts* opts);
#endif
+59
View File
@@ -0,0 +1,59 @@
#define LOG_MODULE "util-patch"
#include <sys/mman.h>
#include "util/log.h"
#include "util/patch.h"
/* addr needs to be a multiple of page size */
#define UNPROTECT(addr,len) mprotect((void*)(addr-(addr%4096)),(addr%4096) + \
len,PROT_READ|PROT_WRITE|PROT_EXEC)
void util_patch_write_memory(uintptr_t mem, const void* data, size_t len)
{
if (UNPROTECT(mem, len) != 0) {
log_die("Unprotecting memory %p, len %d failed", mem, len);
}
memcpy((void*) mem, data, len);
}
void util_patch_write_memory_byte(uintptr_t mem, uint8_t data)
{
util_patch_write_memory(mem, (const void*) &data, sizeof(uint8_t));
}
void util_patch_function(uintptr_t func_addr, void* detour_func)
{
/* uintptr_t is said to be portable (32/64-bit) */
uint8_t offset = 5;
/* 64-bit binary */
if (sizeof(uintptr_t) == 8) {
offset += 4;
}
uintptr_t call =
(uintptr_t) (((uintptr_t) detour_func) - func_addr - offset);
if (UNPROTECT(func_addr, 4096) != 0) {
log_die("Unprotecting memory %p, len %d failed", func_addr);
}
*((uint8_t*) (func_addr)) = 0xE9;
*((uintptr_t*) (func_addr + 1)) = call;
}
void* util_patch_find_signiture(const uint8_t* sig, uint32_t sig_len,
int32_t sig_offset, void* start_addr, void* end_addr, int32_t alignment)
{
size_t pos;
for (pos = (size_t) start_addr; pos < (size_t) end_addr; pos += alignment) {
if (!memcmp((void*) pos, sig, sig_len)) {
return (void*) (pos + sig_offset);
}
}
return NULL;
}
+52
View File
@@ -0,0 +1,52 @@
#ifndef UTIL_PATCH_H
#define UTIL_PATCH_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/**
* Write data to an arbitrary memory location
*
* @param mem Memory location to write to
* @param data Pointer to buffer with data to write
* @param len Length of data to write
*/
void util_patch_write_memory(uintptr_t mem, const void* data, size_t len);
/**
* Write a single byte to an arbitrary memory location
*
* @param mem Memory location to write to
* @param data Byte to write
*/
void util_patch_write_memory_byte(uintptr_t mem, uint8_t data);
/**
* Write a function ptr/function call to a memory location
*
* Use this to patch existing call instructions and detour to your own code
*
* @param func_addr Address of the function/call instruction to replace
* @param detour_func Address of your function to detour to
*/
void util_patch_function(uintptr_t func_addr, void* detour_func);
/**
* Scan a memory area limited by a start and end address for a signiture.
*
* @param sig Buffer with signiture to search for
* @param sig_len Length of signiture
* @param sig_offset Offset that gets added to the address where the signiture
* starts (if found)
* @param start_addr Pointer to the address to start searching at
* @param end_addr Pointer to the address to stop searching at
* @param alignment Aligns the search signiture, i.e. search in steps of
* X bytes
* @return If found, pointer to memory where the signiture was found (first
* occurance) with the signiture offset added, NULL otherwise
*/
void* util_patch_find_signiture(const uint8_t* sig, uint32_t sig_len,
int32_t sig_offset, void* start_addr, void* end_addr, int32_t alignment);
#endif
+218
View File
@@ -0,0 +1,218 @@
#define LOG_MODULE "util-proc"
#include <errno.h>
#include <linux/limits.h>
#include <string.h>
#include <unistd.h>
#include "util/log.h"
#include "util/proc.h"
#include "util/str.h"
static char* util_sys_read_entries_from_proc_file(const char* path, int* count_out)
{
const char* sep = "\n";
char* str = util_str_dup("");
char* tmp;
FILE* cmdline = fopen(path, "rb");
if (!cmdline) {
log_error("Opening %s failed: %s", path, strerror(errno));
return str;
}
char* arg = 0;
size_t size = 0;
int count = 0;
while (getdelim(&arg, &size, 0, cmdline) != -1) {
if (strlen(str) > 0) {
tmp = util_str_merge(str, sep);
free(str);
str = tmp;
}
tmp = util_str_merge(str, arg);
free(str);
str = tmp;
count++;
}
free(arg);
fclose(cmdline);
if (count_out) {
*count_out = count;
}
return str;
}
static void util_proc_log_current_working_dir()
{
char tmp[PATH_MAX];
if (!getcwd(tmp, sizeof(tmp))) {
log_error("Getting current working directory failed");
} else {
log_info("Current working directory: %s", tmp);
}
}
static void util_proc_log_current_process()
{
log_info("PID: %d", getpid());
}
static void util_sys_info_log_path_executable()
{
char buffer[PATH_MAX];
if (!util_proc_get_path_executable(buffer, sizeof(buffer))) {
log_error("Getting path of executable failed");
} else {
log_info("Executable: %s", buffer);
}
}
static void util_sys_info_log_user()
{
log_info("User: %d", getuid());
}
static void util_sys_info_log_running_as_root()
{
log_info("Running as root: %d", util_proc_is_running_as_root());
}
static void util_sys_info_log_cmd_line_args()
{
int count;
char* str = util_sys_read_entries_from_proc_file("/proc/self/cmdline", &count);
log_info("Cmd arguments (%d):\n%s", count, str);
free(str);
}
static void util_sys_info_log_env_vars()
{
int count;
char* str = util_sys_read_entries_from_proc_file("/proc/self/environ", &count);
log_info("Environment variables (%d):\n%s", count, str);
free(str);
}
bool util_proc_is_running_as_root()
{
return getuid() == 0;
}
bool util_proc_get_path_executable(char* buffer, size_t size)
{
// readlink does not null terminate
memset(buffer, 0, size);
return readlink("/proc/self/exe", buffer, size) != -1;
}
bool util_proc_get_folder_path_executable(char* buffer, size_t size)
{
if (!util_proc_get_path_executable(buffer, size)) {
return false;
}
size_t pos = strlen(buffer) - 1;
// If executable in the root folder, keep the single /
while (pos > 0 && buffer[pos] != '/') {
buffer[pos] = '\0';
pos--;
}
// delete /
if (pos > 0) {
buffer[pos] = '\0';
}
return true;
}
bool util_proc_get_folder_path_executable_no_ld_linux(char* buffer, size_t size)
{
if (!util_proc_get_path_executable(buffer, size)) {
log_error("Getting executable path failed");
return false;
}
if (util_str_ends_with(buffer, "ld-linux.so.2")) {
int argc;
char* args = util_sys_read_entries_from_proc_file("/proc/self/cmdline", &argc);
char* tok = strtok(args, "\n");
bool awaiting_value = false;
// Skip first token, ld-linux binary
tok = strtok(NULL, "\n");
while (tok != NULL) {
// Check if the next arg is declaring an option key for ld-linux
if (util_str_starts_with(tok, "--")) {
awaiting_value = 1;
} else if (awaiting_value) {
// Just hit the awaited value for the previously skipped option key
awaiting_value = false;
} else {
// Got executable arg passed to ld-linux
if (strlen(tok) > size) {
free(args);
return false;
}
strcpy(buffer, tok);
// Remove executable name
// If executable in the root folder, keep the single /
size_t pos = strlen(buffer) - 1;
while (pos > 0 && buffer[pos] != '/') {
buffer[pos] = '\0';
pos--;
}
// delete /
if (pos > 0) {
buffer[pos] = '\0';
}
free(args);
return true;
}
tok = strtok(NULL, "\n");
}
free(args);
return false;
} else {
return util_proc_get_folder_path_executable(buffer, size);
}
}
void util_proc_log_info()
{
log_info("================================ Current process information ================================");
util_proc_log_current_process();
util_sys_info_log_path_executable();
util_proc_log_current_working_dir();
util_sys_info_log_user();
util_sys_info_log_running_as_root();
util_sys_info_log_cmd_line_args();
util_sys_info_log_env_vars();
log_info("================================================================================================");
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef UTIL_PROC_H
#define UTIL_PROC_H
#include <stdbool.h>
#include <stdlib.h>
/**
* Check if the current process is running as a root user.
*
* @return True if running as root, false otherwise.
*/
bool util_proc_is_running_as_root();
/**
* Get the full path of the executable of the current process (including the executable name).
*
* @param buffer Buffer to read the path into.
* @param size Size of the buffer
* @return True on success, false on failure, e.g. buffer too small.
*/
bool util_proc_get_path_executable(char* buffer, size_t size);
/**
* Get the full path of the folder the executable of the current process is located in.
*
* @param buffer Buffer to read the path into.
* @param size Size of the buffer
* @return True on success, false on failure, e.g. buffer too small.
*/
bool util_proc_get_folder_path_executable(char* buffer, size_t size);
/**
* Special version of util_proc_get_folder_path_executable that considers when the process is run explicitly with a
* ld-linux binary. Returns the path of the application's executable and not ld-linux in that case.
*
* @param buffer Buffer to read the path into.
* @param size Size of the buffer
* @return True on success, false on failure, e.g. buffer too small.
*/
bool util_proc_get_folder_path_executable_no_ld_linux(char* buffer, size_t size);
/**
* Log information about the current process to the console.
*/
void util_proc_log_info();
#endif
+34
View File
@@ -0,0 +1,34 @@
#include <time.h>
#include <stdlib.h>
#include "rand.h"
static int _util_rand_init = 0;
static void _util_rand_initialize()
{
if (!_util_rand_init) {
_util_rand_init = 1;
srand((unsigned int) time(NULL));
}
}
uint32_t util_rand_gen_32()
{
_util_rand_initialize();
return (uint32_t) rand();
}
uint64_t util_rand_gen_64()
{
uint64_t value;
_util_rand_initialize();
value = 0;
value |= (((uint64_t) rand()) << 32);
value |= ((uint64_t) rand());
return value;
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef UTIL_RAND_H
#define UTIL_RAND_H
#include <stdint.h>
uint32_t util_rand_gen_32();
uint64_t util_rand_gen_64();
#endif
+185
View File
@@ -0,0 +1,185 @@
#define LOG_MODULE "sock-tcp"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "util/net.h"
#include "util/log.h"
#include "util/sock-tcp.h"
bool util_sock_tcp_is_connectable(const char* ipv4, uint32_t timeout_ms)
{
char* address;
uint16_t port;
util_net_split_ipv4_str(ipv4, &address, &port);
bool res = util_sock_tcp_is_connectable2(address, port, timeout_ms);
free(address);
return res;
}
bool util_sock_tcp_is_connectable2(const char* ipv4, uint16_t port, uint32_t timeout_ms)
{
struct sockaddr_in sa;
// store this IP address in sa:
inet_pton(AF_INET, ipv4, &(sa.sin_addr));
return util_sock_tcp_is_connectable3(htonl(sa.sin_addr.s_addr), port, timeout_ms);
}
bool util_sock_tcp_is_connectable3(uint32_t ipv4, uint16_t port, uint32_t timeout_ms)
{
int handle;
struct sockaddr_in addr;
fd_set fdset;
struct timeval tv;
bool res;
handle = socket(AF_INET, SOCK_STREAM, 0);
if (handle == -1) {
log_error("Creating socket (%X, %d) failed: %s", ipv4, port, strerror(errno));
return false;
}
fcntl(handle, F_SETFL, O_NONBLOCK);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(ipv4);
connect(handle, (const struct sockaddr*) &addr, sizeof(addr));
FD_ZERO(&fdset);
FD_SET(handle, &fdset);
tv.tv_sec = (__time_t) (timeout_ms / 1000);
tv.tv_usec = (__suseconds_t) ((timeout_ms % 1000) * 1000);
if (select(handle + 1, NULL, &fdset, NULL, &tv) == 1) {
int so_error;
socklen_t len = sizeof(so_error);
getsockopt(handle, SOL_SOCKET, SO_ERROR, &so_error, &len);
if (so_error == 0) {
res = true;
} else {
res = false;
}
} else {
res = false;
}
close(handle);
return res;
}
int util_sock_tcp_connect(const char* ipv4)
{
char* address;
uint16_t port;
util_net_split_ipv4_str(ipv4, &address, &port);
int res = util_sock_tcp_connect2(address, port);
free(address);
return res;
}
int util_sock_tcp_connect2(const char* ipv4, uint16_t port)
{
struct sockaddr_in sa;
// store this IP address in sa:
inet_pton(AF_INET, ipv4, &(sa.sin_addr));
return util_sock_tcp_connect3(htonl(sa.sin_addr.s_addr), port);
}
int util_sock_tcp_connect3(uint32_t ipv4, uint16_t port)
{
int handle;
struct sockaddr_in addr;
handle = socket(AF_INET, SOCK_STREAM, 0);
if (handle == -1) {
log_error("Creating socket (%X, %d) failed: %s", ipv4, port, strerror(errno));
return -1;
}
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(ipv4);
if (connect(handle, (const struct sockaddr*) &addr, sizeof(addr)) == -1) {
close(handle);
log_error("Connecting to %X, %d failed: %s", ipv4, port, strerror(errno));
return -1;
}
log_debug("Connected to %X on port %d", ipv4, port);
return handle;
}
ssize_t util_sock_tcp_send(int handle, void* buffer, size_t size, uint32_t timeout_ms)
{
struct timeval tv;
tv.tv_sec = (__time_t) (timeout_ms / 1000);
tv.tv_usec = (__suseconds_t) ((timeout_ms % 1000) * 1000);
setsockopt(handle, SOL_SOCKET, SO_SNDTIMEO, (const char*) &tv, sizeof(tv));
ssize_t length = send(handle, buffer, size, 0);
if (length < 0) {
// same as EWOULDBLOCK
if (errno == EAGAIN) {
// no data for non blocking
return 0;
}
return -1;
}
return length;
}
ssize_t util_sock_tcp_recv(int handle, void* buffer, size_t size, uint32_t timeout_ms)
{
struct timeval tv;
tv.tv_sec = (__time_t) (timeout_ms / 1000);
tv.tv_usec = (__suseconds_t) ((timeout_ms % 1000) * 1000);
setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(tv));
ssize_t length = recv(handle, buffer, size, 0);
if (length < 0) {
// same as EWOULDBLOCK
if (errno == EAGAIN) {
// no data for non blocking
return 0;
}
return -1;
}
return length;
}
void util_sock_tcp_close(int handle)
{
close(handle);
}
+30
View File
@@ -0,0 +1,30 @@
//
// Created by on 9/16/18.
//
#ifndef UTIL_SOCK_TCP_H
#define UTIL_SOCK_TCP_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
bool util_sock_tcp_is_connectable(const char* ipv4, uint32_t timeout_ms);
bool util_sock_tcp_is_connectable2(const char* ipv4, uint16_t port, uint32_t timeout_ms);
bool util_sock_tcp_is_connectable3(uint32_t ipv4, uint16_t port, uint32_t timeout_ms);
int util_sock_tcp_connect(const char* ipv4);
int util_sock_tcp_connect2(const char* ipv4, uint16_t port);
int util_sock_tcp_connect3(uint32_t ipv4, uint16_t port);
ssize_t util_sock_tcp_send(int handle, void* buffer, size_t size, uint32_t timeout_ms);
ssize_t util_sock_tcp_recv(int handle, void* buffer, size_t size, uint32_t timeout_ms);
void util_sock_tcp_close(int handle);
#endif
+212
View File
@@ -0,0 +1,212 @@
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util/log.h"
#include "util/mem.h"
#include "util/str.h"
bool util_str_starts_with(const char* haystack, const char* needle)
{
size_t haystack_len;
size_t needle_len;
haystack_len = strlen(haystack);
needle_len = strlen(needle);
if (needle_len > haystack_len) {
return false;
}
return !memcmp(haystack, needle, needle_len);
}
bool util_str_ends_with(const char* haystack, const char* needle)
{
size_t haystack_len;
size_t needle_len;
haystack_len = strlen(haystack);
needle_len = strlen(needle);
if (needle_len > haystack_len) {
return false;
}
return !memcmp(&haystack[haystack_len - needle_len], needle, needle_len);
}
size_t util_str_format(char* buf, size_t nchars, const char* fmt, ...)
{
va_list ap;
size_t result;
va_start(ap, fmt);
result = util_str_vformat(buf, nchars, fmt, ap);
va_end(ap);
return result;
}
size_t util_str_vformat(char* buf, size_t nchars, const char* fmt, va_list ap)
{
int result;
result = vsnprintf(buf, nchars, fmt, ap);
if (result >= (int) nchars || result < 0) {
abort();
}
return (size_t) result;
}
void util_str_cat(char* dest, size_t dnchars, const char* src)
{
size_t dlen;
size_t slen;
dlen = strlen(dest);
slen = strlen(src);
if (dlen + slen >= dnchars) {
abort();
}
memcpy(dest + dlen, src, (slen + 1) * sizeof(char));
}
void util_str_cpy(char* dest, size_t dnchars, const char* src)
{
size_t slen;
slen = strlen(src);
if (slen >= dnchars) {
abort();
}
memcpy(dest, src, (slen + 1) * sizeof(char));
}
char* util_str_merge(const char* str1, const char* str2)
{
char* out;
size_t str1_len;
size_t str2_len;
size_t total;
str1_len = strlen(str1);
str2_len = strlen(str2);
total = str1_len + str2_len + 1;
out = util_xmalloc(total);
memcpy(out, str1, str1_len);
memcpy(out + str1_len, str2, str2_len);
out[total - 1] = '\0';
return out;
}
char* util_str_dup(const char* str)
{
char *dest;
size_t nbytes;
log_assert(str);
nbytes = strlen(str) + 1;
dest = util_xmalloc(nbytes);
memcpy(dest, str, nbytes);
return dest;
}
void util_str_trim(char* str)
{
char *pos;
for (pos = str + strlen(str) - 1 ; pos > str ; pos--) {
if (!isspace(*pos)) {
return;
}
*pos = '\0';
}
}
char* util_str_buffer(const uint8_t* buf, size_t len)
{
char* ret;
size_t pos;
pos = 0;
ret = util_xmalloc(len * 3 + 1);
for (size_t i = 0; i < len; i++) {
uint8_t tmp = buf[i];
pos += sprintf(ret + pos, "%02X ", tmp);
}
ret[len * 3] = '\0';
return ret;
}
char** util_str_split(const char* str, const char* delim, size_t* count)
{
char** toks;
char* copy;
char* cur;
size_t counter;
log_assert(str);
log_assert(delim);
log_assert(count);
*count = 0;
copy = util_str_dup(str);
cur = strtok(copy, delim);
// First iteration, just count items
while (cur != NULL) {
(*count)++;
cur = strtok(NULL, delim);
}
util_xfree((void**) &copy);
toks = util_xmalloc(sizeof(char*) * (*count));
copy = util_str_dup(str);
cur = strtok(copy, delim);
counter = 0;
// Second iteration, grab tokens
while (cur != NULL) {
toks[counter] = util_str_dup(cur);
counter++;
cur = strtok(NULL, delim);
}
util_xfree((void**) &copy);
return toks;
}
void util_str_free_split(char** split, size_t count)
{
log_assert(split);
for (int i = 0; i < count; i++) {
util_xfree((void**) &split[i]);
}
util_xfree((void**) &split);
}
+107
View File
@@ -0,0 +1,107 @@
#ifndef UTIL_STR_H
#define UTIL_STR_H
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
/**
* Check if a string starts with a specific (sub-) string
*
* @param haystack String to check
* @param needle String to compare with start of haystack
* @return True if haystack ends with needle, false otherwise
*/
bool util_str_starts_with(const char* haystack, const char* needle);
/**
* Check if a string ends with a specific (sub-) string
*
* @param haystack String to check
* @param needle String to compare with end of haystack
* @return True if haystack ends with needle, false otherwise
*/
bool util_str_ends_with(const char* haystack, const char* needle);
/**
* Print a formated string to a buffer
*
* @param buf Allocated buffer to print to
* @param nchars Size of allocated buffer
* @param fmt Format of the string to print
* @param ... Arguments for the format string
* @return Size of the string printed to the buffer
*/
size_t util_str_format(char* buf, size_t nchars, const char* fmt, ...);
/**
* Print a formated string to a buffer
*
* @param buf Allocated buffer to print to
* @param nchars Size of allocated buffer
* @param fmt Format of the string to print
* @param ap Argument list for format
* @return Size of the string printed to the buffer
*/
size_t util_str_vformat(char* buf, size_t nchars, const char* fmt, va_list ap);
/**
* Concat a string to another one
*
* @param dest Destination to append to
* @param dnchars Size of dest buffer
* @param src Source string to concat to dest
*/
void util_str_cat(char* dest, size_t dnchars, const char* src);
/**
* Copy a string
*
* @param dest Destination to copy to
* @param dnchars Size of destination
* @param src Source string to copy from (to dest)
*/
void util_str_cpy(char* dest, size_t dnchars, const char* src);
/**
* Merge to strings (str1 + str2)
*
* @param str1 String 1 to merge
* @param str2 String 2 to merge
* @return Newly allocated merged string: str1 + str2. Caller has to manage
* memory returned
*/
char* util_str_merge(const char* str1, const char* str2);
/**
* Duplicate a string
*
* @param src String to duplicate
* @return Duplicated string (newly allocated memory). Caller has to manage
* memory returned
*/
char* util_str_dup(const char* src);
/**
* Remove trailing spaces of a string
*
* @param str String to trim
*/
void util_str_trim(char* str);
/**
* Print a buffer as hex digits to a string
*
* @param buf Buffer to print
* @param len Length of the buffer
* @return String representation of the buffer. Caller has to manage returned
* memory
*/
char* util_str_buffer(const uint8_t* buf, size_t len);
char** util_str_split(const char* str, const char* delim, size_t* count);
void util_str_free_split(char** split, size_t count);
#endif
+22
View File
@@ -0,0 +1,22 @@
#define LOG_MODULE "util-sys-info"
#include <sys/utsname.h>
#include "util/log.h"
static void util_sys_info_log_kernel()
{
struct utsname buf;
if (uname(&buf)) {
log_error("Reading kernel version failed");
return;
}
log_info("%s|%s|%s|%s|%s", buf.sysname, buf.nodename, buf.release, buf.version, buf.machine);
}
void util_sys_info_log()
{
util_sys_info_log_kernel();
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef UTILSYS_INFO_H
#define UTIL_SYS_INFO_H
/**
* Print system information to the log (kernel, cpu, ram etc)
*/
void util_sys_info_log();
#endif
+159
View File
@@ -0,0 +1,159 @@
#define LOG_MODULE "util-test"
#include <string.h>
#include "list.h"
#include "log.h"
#include "mem.h"
#include "test.h"
#include "str.h"
struct util_test_case {
struct util_list_node head;
char* name;
util_test_func_t func;
};
static size_t util_test_count;
static struct util_list util_test_list;
void util_test_init()
{
util_test_count = 0;
util_list_init(&util_test_list);
log_info("Initialized");
}
void util_test_add(const char* name, util_test_func_t func)
{
struct util_test_case* test;
test = util_xmalloc(sizeof(struct util_test_case));
test->name = util_str_dup(name);
test->func = func;
util_list_append(&util_test_list, &test->head);
util_test_count++;
log_info("Added %s, func %p", name, func);
}
void util_test_exec()
{
log_info("Exec %d tests", util_test_count);
struct util_list_node* pos;
struct util_test_case* test;
size_t counter = 1;
for (pos = util_test_list.head; pos != NULL; pos = pos->next) {
test = containerof(pos, struct util_test_case, head);
log_debug("%d/%d Executing %s...", counter++, util_test_count, test->name);
if (!test->func()) {
log_error("%s failed", test->name);
return;
}
}
log_info("All tests passed");
}
void util_test_shutdown()
{
log_info("Shutdown");
struct util_list_node* pos;
struct util_test_case* test;
// TODO list elems cleanup?
for (pos = util_test_list.head; pos != NULL; pos = pos->next) {
test = containerof(pos, struct util_test_case, head);
free(test->name);
}
}
bool util_test_assert_exp(bool exp, const char* exp_str, const char* file, size_t line_num)
{
if (!exp) {
log_error("Assert failed [%s:%d]: Expression %s failed", file, line_num, exp_str);
return false;
} else {
log_debug("Assert successful [%s:%d]: Expression %s", file, line_num, exp_str);
return true;
}
}
bool util_test_assert_uint(size_t val_exp, size_t val_actual, const char* exp, const char* actual, const char* file,
size_t line_num)
{
if (val_exp != val_actual) {
log_error("Assert failed [%s:%d]: %d != %d of expected %s and actual %s", file, line_num, val_exp, val_actual,
exp, actual);
return false;
} else {
log_debug("Assert successful [%s:%d]: %d == %d of expected %s and actual %s", file, line_num, val_exp,
val_actual, exp, actual);
return true;
}
}
bool util_test_assert_str(const char* val_exp, const char* val_actual, const char* exp, const char* actual,
const char* file, size_t line_num)
{
if (strcmp(val_exp, val_actual) != 0) {
log_error("Assert failed [%s:%d]: %s != %s of expected %s and actual %s", file, line_num, val_exp, val_actual,
exp, actual);
return false;
} else {
log_debug("Assert successful [%s:%d]: %s == %s of expected %s and actual %s", file, line_num, val_exp,
val_actual, exp, actual);
return true;
}
}
bool util_test_assert_data(const void* data_exp, const void* data_actual, size_t len, const char* exp,
const char* actual, const char* file, size_t line_num)
{
bool ret;
char* data_exp_str = util_str_buffer(data_exp, len);
char* data_actual_str = util_str_buffer(data_actual, len);
if (memcmp(data_exp, data_actual, len) != 0) {
log_error("Assert failed [%s:%d]: %s != %s of expected %s and actual %s", file, line_num, data_exp_str,
data_actual_str, exp, actual);
uint32_t cnt = 0;
for (size_t i = 0; i < len; i++) {
/* print the first 5 diffs, only */
if (((const uint8_t*) data_exp)[i] != ((const uint8_t*) data_actual)[i]) {
if (cnt < 5) {
log_error("pos %d: %x != %x", i, ((const uint8_t*) data_exp)[i], ((const uint8_t*) data_actual)[i]);
}
cnt++;
}
}
if (cnt > 5) {
log_error("...and more different bytes, total diffs %d", cnt);
}
ret = false;
} else {
log_debug("Assert successful [%s:%d]: %s == %s of expected %s and actual %s", file, line_num, data_exp_str,
data_actual_str, exp, actual);
ret = true;
}
free(data_exp_str);
free(data_actual_str);
return ret;
}
+81
View File
@@ -0,0 +1,81 @@
#ifndef UTIL_TEST_H
#define UTIL_TEST_H
#include <stdbool.h>
#include <stdlib.h>
#include "defs.h"
#include "log.h"
#define UTIL_TEST_MAIN_START \
int main() \
{ \
log_info("Unit test %s", FILENAME); \
util_test_init(); \
#define UTIL_TEST_MAIN_END \
util_test_exec(); \
util_test_shutdown(); \
return 0; \
} \
#define UTIL_TEST_FUNC_START(name) \
bool name() \
{ \
#define UTIL_TEST_FUNC_END \
return true; \
} \
#define UTIL_TEST_ADD(func) util_test_add(STRINGIFY(func), func);
#define UTIL_TEST_ASSERT(exp) \
do { \
if (!util_test_assert_exp(exp, STRINGIFY(exp), FILENAME, __LINE__)) { \
return false; \
} \
} while (0); \
#define UTIL_TEST_ASSERT_UINT(exp, actual) \
do { \
if (!util_test_assert_uint(exp, actual, STRINGIFY(exp), STRINGIFY(actual), FILENAME, __LINE__)) { \
return false; \
} \
} while (0); \
#define UTIL_TEST_ASSERT_STR(exp, actual) \
do { \
if (!util_test_assert_str(exp, actual, STRINGIFY(exp), STRINGIFY(actual), FILENAME, __LINE__)) { \
return false; \
} \
} while (0); \
#define UTIL_TEST_ASSERT_DATA(exp, actual, len) \
do { \
if (!util_test_assert_data(exp, actual, len, STRINGIFY(exp), STRINGIFY(actual), FILENAME, __LINE__)) { \
return false; \
} \
} while (0); \
typedef bool (*util_test_func_t)();
void util_test_init();
void util_test_add(const char* name, util_test_func_t func);
void util_test_exec();
void util_test_shutdown();
bool util_test_assert_exp(bool exp, const char* exp_str, const char* file, size_t line_num);
bool util_test_assert_uint(size_t val_exp, size_t val_actual, const char* exp, const char* actual, const char* file,
size_t line_num);
bool util_test_assert_str(const char* val_exp, const char* val_actual, const char* exp, const char* actual,
const char* file, size_t line_num);
bool util_test_assert_data(const void* data_exp, const void* data_actual, size_t len, const char* exp,
const char* actual, const char* file, size_t line_num);
#endif
+69
View File
@@ -0,0 +1,69 @@
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "util/time.h"
#define SEC_PER_DAY 86400
#define SEC_PER_HOUR 3600
#define SEC_PER_MIN 60
void util_time_sleep_ns(uint64_t time_ns)
{
struct timespec t;
t.tv_sec = (__time_t) (time_ns / (1000 * 1000 * 1000));
t.tv_nsec = (__syscall_slong_t) time_ns % (1000 * 1000 * 1000);
nanosleep(&t, NULL);
}
void util_time_sleep_us(uint64_t time_us)
{
struct timespec t;
t.tv_sec = (__time_t) (time_us / (1000 * 1000));
t.tv_nsec = (__syscall_slong_t) (time_us % (1000 * 1000)) * 1000;
nanosleep(&t, NULL);
}
void util_time_sleep_ms(uint64_t time_ms)
{
struct timespec t;
t.tv_sec = (__time_t) (time_ms / 1000);
t.tv_nsec = (__syscall_slong_t) (time_ms % 1000) * 1000 * 1000;
nanosleep(&t, NULL);
}
void util_time_sleep_sec(uint64_t time_sec)
{
struct timespec t;
t.tv_sec = (__time_t) time_sec;
t.tv_nsec = 0;
nanosleep(&t, NULL);
}
void util_time_get_current_time(struct util_time_timestamp* timestamp)
{
if (!timestamp) {
return;
}
time_t t = time(NULL);
struct tm* tm = localtime(&t);
struct timeval tv;
gettimeofday(&tv, NULL);
timestamp->millisec = tv.tv_usec / 1000;
timestamp->sec = tm->tm_sec;
timestamp->min = tm->tm_min;
timestamp->hour = tm->tm_hour;
timestamp->day = tm->tm_mday;
// Months since January [0, 11]
timestamp->month = tm->tm_mon + 1;
// Years since 1900
timestamp->year = tm->tm_year + 1900;
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef UTIL_TIME_H
#define UTIL_TIME_H
#include <stdint.h>
struct util_time_timestamp {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint16_t millisec;
};
void util_time_sleep_ns(uint64_t time_ns);
void util_time_sleep_us(uint64_t time_us);
void util_time_sleep_ms(uint64_t time_ms);
void util_time_sleep_sec(uint64_t time_sec);
void util_time_get_current_time(struct util_time_timestamp* timestamp);
#endif //UTIL_TIME_H