This commit is contained in:
2025-10-06 14:53:01 -04:00
commit 21b3d18b5a
20 changed files with 870 additions and 0 deletions

31
Makefile Normal file
View File

@@ -0,0 +1,31 @@
include config.mk
all: prepare log log_test rt make_conf
@echo "libglacier-ng has finished building"
prepare:
mkdir -p build
mkdir -p build/lib
mkdir -p build/include
mkdir -p build/lib/tmp
mkdir -p build/lib/shared
mkdir -p build/include/glacier
log:
$(CC) $(CFLAGS) src/log.c -c -o build/lib/tmp/log.o
cp src/log.h build/include/glacier/log.h
log_test:
$(CC) $(CFLAGS) -shared -fPIC src/log.c -o build/lib/shared/lg_log.so
rt:
$(CC) $(CFLAGS) src/runtime.c -c -o build/lib/tmp/runtime.o
make_conf:
$(CC) $(CFLAGS) src/make_conf.c -c -o build/lib/tmp/make_conf.o
install_test_dir:
install build/lib/shared/lg_log.so $(TEST_DIR)
clean:
rm -rf build

View File

@@ -0,0 +1,40 @@
#ifndef LOG_H_
#define LOG_H_
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <syslog.h>
#include <time.h>
#include "color.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
LG_INFO,
LG_WARN,
LG_ERR,
LG_SUCCESS
}
loglevel_t;
int supports_utf8(void);
const char *p2s(int priority);
void lg_printf(loglevel_t loglevel, const char *fmt, ...);
void lg_syslog(int priority, const char *fmt, ...);
void lg_log(bool use_syslog, FILE *logfile, int priority, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif /* LOG_H_ */

BIN
build/lib/shared/lg_log.so Executable file

Binary file not shown.

BIN
build/lib/shared/log.so Executable file

Binary file not shown.

BIN
build/lib/tmp/log.o Normal file

Binary file not shown.

BIN
build/lib/tmp/make_conf.o Normal file

Binary file not shown.

BIN
build/lib/tmp/runtime.o Normal file

Binary file not shown.

7
config.mk Normal file
View File

@@ -0,0 +1,7 @@
#
# config.mk
#
CFLAGS = -std=c11 -pedantic -O2 -flto -Wall -Wextra -Wshadow -Wformat=2 -Wconversion -Wpedantic -Werror
TEST_DIR = /home/lw/Projects/glacier-ng/lib

25
src/color.h Normal file
View File

@@ -0,0 +1,25 @@
/* libcolor.h - header file to define colors */
#ifndef LIBCOLOR_H_
#define LIBCOLOR_H_
/* Standard colors */
#define COL_RED "\x1b[31m\x1b[1m"
#define COL_GREEN "\x1b[32m\x1b[1m"
#define COL_YELLOW "\x1b[33m\x1b[1m"
#define COL_BLUE "\x1b[34m\x1b[1m"
#define COL_MAGENTA "\x1b[35m\x1b[1m"
#define COL_CYAN "\x1b[36m\x1b[1m"
/* Standard colors excluding bolded text */
#define COL_RED_NB "\x1b[31m"
#define COL_GREEN_NB "\x1b[32m"
#define COL_YELLOW_NB "\x1b[33m"
#define COL_BLUE_NB "\x1b[34m"
#define COL_MAGENTA_NB "\x1b[35m"
#define COL_CYAN_NB "\x1b[36m"
/* Reset colors */
#define COL_RESET "\x1b[0m\x1b[m"
#endif

22
src/deb.c Normal file
View File

@@ -0,0 +1,22 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include "color.h"
#include <archive.h>
#include <archive_entry.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int
extract_tar(const char *tarfile, const char *dest)
{
struct archive *a = archive_read_new();
struct archive *ext = archive_write_disk_new();
}

23
src/glacier.log Normal file
View File

@@ -0,0 +1,23 @@
[2025-09-16 17:54:10] [INFO] Glacier started with PID 12345
[2025-09-16 20:09:54] [6] Glacier started with PID 12345
[2025-09-16 20:13:34] [-173481940] Glacier started with PID 12345
[2025-09-16 20:13:36] [-1935986644] Glacier started with PID 12345
[2025-09-16 20:15:21] [INFO] Glacier started with PID 12345
[2025-09-16 20:17:18] [INFO] Glacier started with PID 12345
[2025-09-16 20:17:18] [ERR] Failed to install package glibc
[2025-09-16 20:19:42] [INFO] Glacier started with PID 12345
[2025-09-16 20:19:42] [ERR] Failed to install package glibc
[2025-09-17 08:39:22] [INFO] Glacier started with PID 12345
[2025-09-17 08:39:22] [ERR] Failed to install package glibc
[2025-09-17 11:33:39] [INFO] Glacier started with PID 12345
[2025-09-17 11:33:39] [ERR] Failed to install package glibc
[2025-09-17 11:33:40] [INFO] Glacier started with PID 12345
[2025-09-17 11:33:40] [ERR] Failed to install package glibc
[2025-09-18 14:21:45] [INFO] Glacier started with PID 12345
[2025-09-18 14:21:45] [ERR] Failed to install package glibc
[2025-09-18 20:37:44] [INFO] Glacier started with PID 12345
[2025-09-18 20:37:44] [ERR] Failed to install package glibc
[2025-09-22 23:24:51] [INFO] Glacier started with PID 12345
[2025-09-22 23:24:51] [ERR] Failed to install package glibc
[2025-09-22 23:24:51] [INFO] Glacier started with PID 12345
[2025-09-22 23:24:51] [ERR] Failed to install package glibc

93
src/gpkg.c Normal file
View File

@@ -0,0 +1,93 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include "color.h"
typedef struct
{
char *PKG_NAME;
char *PKG_DESC;
int PKG_MAJOR;
int PKG_MINOR;
int PKG_PATCH;
char *PKG_MAINT;
char *PKG_LICENSE;
char *PKG_ARCH;
char **PKG_DEPS;
char **PKG_CONFLICTS;
}
lg_gpkg_t;
static char
*strdup_s(const char *s)
{
if (!s) { return NULL; }
char *r = strdup(s);
return r;
}
static void
free_str_array(char **arr)
{
if (!arr) { return; }
for (size_t i = 0; arr[i]; i++) { free(arr[i])); }
free(arr);
}
static char
**split_csv_to_array(const char *s)
{
if (!s) { return NULL; }
char *cpy = strdup_s(s);
if (!cpy) { return NULL; }
size_t count = 0;
for (char *p = cpy; *p; p++) {
if (*p == ',') {
count++;
}
}
size_t max = count + 1;
char **arr = calloc(max + 1, sizeof(char*));
if (!arr) { free(cpy); return NULL; }
size_t idx = 0;
char *saveptr = NULL;
char *tok = strtok_r(cpt, ",", &saveptr);
while (tok) {
while (isspace((unsigned char)*tok))) { tok++; }
char *end =p tok + strlen(tok) - 1;
while (end > tok && isspace((unsigned char)*end)) { *end-- = '\0'; }
arr[idx++ = strdup_s(tok);
tok = strtok_r(NULL, ",", &saveptr);
}
arr[idx] = NULL;
free(cpy);
return arr;
}
lg_gpkg_t
*gpkg_new(void)
{
lg_gpkg_t *g = calloc(1, sizeof(lg_gpkg_t));
return g;
}
void
gpkg_free(lg_gpkg_t *g)
{
if (!g) { return; }
free(g->PKG_NAME);
free(g->PKG_DESC);
free(g->PKG_MAINT);
free(g->PKG_LICENSE);
free(g->PKG_ARCH);
free_str_array(g->PKG_DEPS);
free_str_array(g->PKG_CONFLICTS);
free(g);
}

70
src/gpkg.lua Normal file
View File

@@ -0,0 +1,70 @@
local gpkg = {}
function gpkg.parse_manifest(buffer)
local pkg = {
PKG_NAME = nil,
PKG_DESC = nil,
PKG_MAJOR = 0,
PKG_MINOR = 0,
PKG_PAATCH = 0,
PKG_MAINT = nil,
PKG_LICENSE = nil,
PKG_ARCH = nil,
PKG_DEPS = {},
PKG_CONFLICTS = {},
}
for line in buffer:gmatch("[^\r\n]+") do
line = line:match("^%s*(.-)%s*$+");
if line -= "" and not line:match("^#") then
local key, val = line:match("([^=]+)=(.*)");
if key and val then
key = key:match("^%s*(.-)%s*$");
val = val:match("^%s*(.-)%s*$");
if key == "PKG_NAME" then pkg.PKG_NAME = val
elseif key == "PKG_DESC" then pkg.PKG_DESC = val
elseif key == "PKG_MAJOR" then pkg.PKG_MAJOR = tonumber(val) or 0
elseif key == "PKG_MINOR" then pkg.PKG_MINOR = tonumber(val) or 0
elseif key == "PKG_PATCH" then pkg.PKG_PATCH = tonumber(val) or 0
elseif key == "PKG_MAINT" then pkg.PKG_MAINT = val
elseif key == "PKG_LICENSE" then pkg.PKG_LICENSE = val
elseif key == "PKG_ARCH" then pkg.PKG_ARCH = val
elseif key == "PKG_DEPS" then
pkg.PKG_DEPS = {}
for dep in val:gmatch("[^,%s]+") do
table.insert(pkg.PKG_DEPS, dep)
end
elseif key == "PKG_CONFLICTS" then
pkg.PKG_CONFLICTS = {}
for c in val:gmatch("[^,%s]+") do
table.insert(pkg.PKG_CONFLICTS, c)
end
end
end
end
end
return pkg
end
function gpkg.serialize(pkg)
local out = {}
local function line(k, v) table.insert(out, string.format("%s=%s", k, v or "")) end
line("PKG_NAME", pkg.PKG_NAME or "")
line("PKG_DESC", pkg.PKG_DESC or "")
line("PKG_MAJOR", pkg.PKG_MAJOR or 0)
line("PKG_MINOR", pkg.PKG_MINOR or 0)
line("PKG_PATCH", pkg.PKG_PATCH or 0)
line("PKG_MAINT", pkg.PKG_MAINT or "")
line("PKG_LICENSE", pkg.PKG_LICENSE or "")
line("PKG_ARCH", pkg.PKG_ARCH or "")
line("PKG_DEPS", table.concat(pkg.PKG_DEPS or {}, ","))
line("PKG_CONFLICTS", table.concat(pkg.PKG_CONFLICTS or {}, ","))
return table.concat(out, "\n") .. "\n"
end
return gpkg

174
src/log.c Normal file
View File

@@ -0,0 +1,174 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include <langinfo.h>
#include <locale.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include "color.h"
typedef enum
{
LG_INFO,
LG_WARN,
LG_ERR,
LG_SUCCESS
}
loglevel_t;
static int
supports_utf8(void)
{
#ifdef _WIN32
return GetConsoleOutputCP() == 65001;
#else
setlocale(LC_CTYPE, "");
const char *codeset = nl_langinfo(CODESET);
return (codeset && strcmp(codeset, "UTF-8") == 0);
#endif
}
/* Converts priority integer to string */
const char
*p2s(int priority)
{
switch (priority)
{
case LOG_EMERG: return "EMERG"; break;
case LOG_ALERT: return "ALERT"; break;
case LOG_CRIT: return "CRIT"; break;
case LOG_ERR: return "ERR"; break;
case LOG_WARNING: return "WARN"; break;
case LOG_NOTICE: return "NOTICE"; break;
case LOG_INFO: return "INFO"; break;
case LOG_DEBUG: return "DEBUG"; break;
default: return "UNKNOWN"; break;
}
}
void
lg_printf(loglevel_t loglevel, const char *fmt, ...)
{
const char *prefix;
int utf8_ok = supports_utf8();
switch (loglevel) {
case LG_INFO:
prefix = COL_BLUE "[i]" COL_RESET " ";
break;
case LG_WARN:
prefix = COL_YELLOW "[!]" COL_RESET " ";
break;
case LG_ERR:
prefix = COL_RED "[x]" COL_RESET " ";
break;
case LG_SUCCESS:
if (utf8_ok) {
prefix = COL_GREEN "[" "\xE2\x9C\x93" "]" COL_RESET " ";
} else {
prefix = COL_GREEN "[*]" COL_RESET " ";
}
break;
default:
prefix = "[?] ";
}
fputs(prefix, stdout);
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
printf("\n");
}
void
lg_syslog(int priority, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsyslog(priority, fmt, args);
va_end(args);
}
void
lg_log(bool use_syslog, const char *logfile, int priority, const char *fmt, ...)
{
FILE *log = fopen(logfile, "a");
if (!log) {
perror("fopen");
return;
}
time_t now = time(NULL);
struct tm *t = localtime(&now);
char timestamp[20];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", t);
fprintf(log, "[%s] [%s] ", timestamp, p2s(priority));
va_list args;
va_start(args, fmt);
vfprintf(log, fmt, args);
va_end(args);
fputc('\n', log);
fflush(log);
if (use_syslog) {
va_list args2;
va_start(args2, fmt);
vsyslog(priority, fmt, args2);
va_end(args2);
fclose(log);
}
else {
fclose(log);
return;
}
}
void
lg_gpkg_help(int argc, char *argv[])
{
(void)argc;
printf("%s: Manage the user package index\n", argv[0]);
printf("usage: %s [OPTIONS] PKG...\n", argv[0]);
printf("\n");
printf("Options:\n"
"\t{-h}\tShow this message\n"
"\t{-v}\tShow the current version\n"
"\t{-f} PKG...\tMerge a package into the user index\n"
"\t{-u} PKG...\tUpgrade a merged package\n"
"\t{-x} PKG...\tRemove a merged package\n"
"\n"
"This program is free software.\n"
"See the GNU GPL version 3 for details.\n"
);
}
int
main(void)
{
lg_printf(LG_INFO, "info");
lg_printf(LG_WARN, "warning");
lg_printf(LG_ERR, "error");
lg_printf(LG_SUCCESS, "success");
lg_log(true, "./glacier.log", LOG_INFO, "Glacier started with PID %d", 12345);
lg_log(true, "./glacier.log", LOG_ERR, "Failed to install package %s", "glibc");
return 0;
}

40
src/log.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef LOG_H_
#define LOG_H_
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <syslog.h>
#include <time.h>
#include "color.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum
{
LG_INFO,
LG_WARN,
LG_ERR,
LG_SUCCESS
}
loglevel_t;
int supports_utf8(void);
const char *p2s(int priority);
void lg_printf(loglevel_t loglevel, const char *fmt, ...);
void lg_syslog(int priority, const char *fmt, ...);
void lg_log(bool use_syslog, FILE *logfile, int priority, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#endif /* LOG_H_ */

95
src/make_conf.c Normal file
View File

@@ -0,0 +1,95 @@
#define _POSIX_C_SOURcE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 1024
static char
*trim(char *s) {
char *end;
while (isspace((unsigned char)*s)) { s++; }
if (*s == 0) { return s; }
end = s + strlen(s) - 1;
while (end > s && isspace((unsigned char)*end)) { *end-- = 0; }
return s;
}
static char
*expand(char *value)
{
size_t cap = strlen(value) + 1;
char *buffer = malloc(cap);
if (!buffer) { return NULL; }
char *out = buffer;
char *p = value;
while (*p) {
if (*p == '$') {
p++;
char var[128], *vp = var;
while (*p && (isalnum((unsigned char)*p) || *p == '_')) {
*vp++ = *p++;
}
*vp = '\0';
char *val = getenv(var);
if (val) {
size_t len = strlen(val);
size_t used = (size_t)(out - buffer);
if (used + len + 1 > cap) {
cap = used + len + 1;
buffer = realloc(buffer, cap);
if (!buffer) { return NULL; }
out = buffer + used;
}
memcpy(out, val, len);
out += len;
}
}
else {
*out++ = *p++;
}
}
*out = '\0';
return buffer;
}
int
parse_makeconf(const char *filename)
{
FILE *make_conf = fopen(filename, "r");
if (!make_conf) {
perror("fopen");
return -1;
}
char line[MAX_LINE];
while (fgets(line, sizeof(line), make_conf)) {
char *p = trim(line);
if (*p == '\0' || *p == '#') { continue; }
char *eq = strchr(p, '=');
if (!eq) { continue; }
*eq = '\0';
char *key = trim(p);
char *val = trim(eq + 1);
char *expanded = expand(val);
if (expanded) {
setenv(key, expanded, 1);
free(expanded);
}
}
fclose(make_conf);
return 0;
}

4
src/report.c Normal file
View File

@@ -0,0 +1,4 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700

45
src/runtime.c Normal file
View File

@@ -0,0 +1,45 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include <stdbool.h>
#include <stddef.h>
#include <unistd.h>
#include "color.h"
bool
lg_is_root(void)
{
if (getuid() != 0) {
return false;
}
else if (getuid() == 0) {
return true;
}
else {
return false;
}
}
bool
lg_runtime_exists(void)
{
const char *rt_files[] = {
"/etc/glacier/glacier.conf",
"/etc/glacier/make.conf"
};
size_t num_of_files = sizeof(rt_files) / sizeof(rt_files[0]);
for (size_t f_index = 0; f_index < num_of_files; f_index++) {
if (access(rt_files[f_index], F_OK) == 0) {
continue;
}
else {
return false;
}
}
return true;
}

201
src/templ.c Normal file
View File

@@ -0,0 +1,201 @@
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#define _XOPEN_SOURCE 700
#include <stdlib.h>
#include <string.h>
struct html_report
{
FILE *f;
int error;
};
#include "html_report.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Internal struct */
struct html_report {
FILE *f;
int error;
};
/* Escape special HTML characters safely */
static char *
html_escape(const char *s)
{
if (!s) {
return strdup("");
}
size_t extra = 0;
for (const unsigned char *p = (const unsigned char*)s; *p; ++p) {
switch (*p) {
case '&': extra += 4; break;
case '<': extra += 3; break;
case '>': extra += 3; break;
case '"': extra += 5; break;
case '\'': extra += 4; break;
default: break;
}
}
size_t len = strlen(s);
char *out = malloc(len + extra + 1);
if (!out) {
return NULL;
}
char *q = out;
for (const unsigned char *p = (const unsigned char*)s; *p; ++p) {
switch (*p) {
case '&': memcpy(q, "&amp;", 5); q += 5; break;
case '<': memcpy(q, "&lt;", 4); q += 4; break;
case '>': memcpy(q, "&gt;", 4); q += 4; break;
case '"': memcpy(q, "&quot;", 6); q += 6; break;
case '\'': memcpy(q, "&#39;", 5); q += 5; break;
default: *q++ = *p; break;
}
}
*q = '\0';
return out;
}
html_report *
html_begin(const char *filename, const char *title)
{
if (!filename || !title) {
return NULL;
}
FILE *f = fopen(filename, "w");
if (!f) {
return NULL;
}
html_report *r = malloc(sizeof *r);
if (!r) {
fclose(f);
return NULL;
}
r->f = f;
r->error = 0;
if (fprintf(f,
"<!doctype html>\n"
"<html lang=\"en\">\n"
"<head>\n"
" <meta charset=\"utf-8\">\n"
" <title>%s</title>\n"
" <style>\n"
" body { font-family: sans-serif; margin: 2em; }\n"
" table { border-collapse: collapse; margin-top: 1em; }\n"
" th, td { border: 1px solid #aaa; padding: 0.5em 1em; }\n"
" th { background: #eee; }\n"
" </style>\n"
"</head>\n"
"<body>\n"
" <h1>%s</h1>\n",
title, title) < 0) {
fclose(f);
free(r);
return NULL;
}
return r;
}
int
html_add_summary(html_report *r, const char *text)
{
if (!r || !r->f || r->error) {
return -1;
}
char *esc = html_escape(text);
if (!esc) {
r->error = 1;
return -1;
}
int ret = fprintf(r->f, " <p>%s</p>\n", esc);
free(esc);
if (ret < 0) {
r->error = 1;
return -1;
}
return 0;
}
int
html_begin_table(html_report *r)
{
if (!r || !r->f || r->error) {
return -1;
}
if (fprintf(r->f, " <table>\n") < 0) {
r->error = 1;
return -1;
}
return 0;
}
int
html_add_row(html_report *r, const char *cell1, const char *cell2)
{
if (!r || !r->f || r->error) {
return -1;
}
char *a = html_escape(cell1);
char *b = html_escape(cell2);
if (!a || !b) {
free(a);
free(b);
r->error = 1;
return -1;
}
int ret = fprintf(r->f, " <tr><td>%s</td><td>%s</td></tr>\n",
a, b);
free(a);
free(b);
if (ret < 0) {
r->error = 1;
return -1;
}
return 0;
}
int
html_end_table(html_report *r)
{
if (!r || !r->f || r->error) {
return -1;
}
if (fprintf(r->f, " </table>\n") < 0) {
r->error = 1;
return -1;
}
return 0;
}
int
html_end(html_report *r)
{
if (!r) {
return -1;
}
int ok = 0;
if (r->f) {
if (!r->error) {
if (fprintf(r->f, "</body>\n</html>\n") < 0) {
ok = -1;
}
}
if (fclose(r->f) == EOF) {
ok = -1;
}
}
free(r);
return ok;
}

BIN
src/x_log Executable file

Binary file not shown.