3/18: Functional package installation backend
This commit is contained in:
44
Makefile
44
Makefile
@@ -1,8 +1,27 @@
|
||||
include config.mk
|
||||
|
||||
all: prepare log log_test rt istoreutils make_conf
|
||||
.PHONY: all prepare log log_test rt pkg istoreutils make_conf dag install clean static libglacier.a install_static
|
||||
|
||||
all: prepare log log_test rt pkg istoreutils make_conf dag
|
||||
@echo "libglacier-ng has finished building"
|
||||
|
||||
static: prepare log_static pkg_static istoreutils_static libglacier.a
|
||||
|
||||
log_static:
|
||||
$(CC) $(CFLAGS) -c src/log.c -o build/lib/tmp/log.o
|
||||
|
||||
pkg_static:
|
||||
$(CC) $(CFLAGS) -c src/pkg.c -o build/lib/tmp/pkg.o
|
||||
|
||||
istoreutils_static: pkg_static
|
||||
$(CC) $(CFLAGS) -c src/istoreutils.c -o build/lib/tmp/istoreutils.o
|
||||
|
||||
libglacier.a:
|
||||
ar rcs build/lib/libglacier.a \
|
||||
build/lib/tmp/log.o \
|
||||
build/lib/tmp/pkg.o \
|
||||
build/lib/tmp/istoreutils.o
|
||||
|
||||
prepare:
|
||||
mkdir -p build
|
||||
mkdir -p build/lib
|
||||
@@ -21,20 +40,37 @@ log_test:
|
||||
rt:
|
||||
$(CC) $(CFLAGS) src/runtime.c -c -o build/lib/tmp/runtime.o
|
||||
|
||||
istoreutils:
|
||||
|
||||
istoreutils: pkg
|
||||
$(CC) $(CFLAGS) -shared -fPIC src/istoreutils.c \
|
||||
-Lbuild/lib/shared -lglacier_log \
|
||||
-Lbuild/lib/shared -lglacier_log -lglacier_pkg -larchive \
|
||||
-Wl,-rpath,'$$ORIGIN' \
|
||||
-o build/lib/shared/libglacier_istoreutils.so
|
||||
|
||||
pkg:
|
||||
$(CC) $(CFLAGS) -shared -fPIC src/pkg.c \
|
||||
-Lbuild/lib/shared -lglacier_log -lconfig \
|
||||
-Wl,-rpath,'$$ORIGIN' \
|
||||
-o build/lib/shared/libglacier_pkg.so
|
||||
|
||||
make_conf:
|
||||
$(CC) $(CFLAGS) src/make_conf.c -c -o build/lib/tmp/make_conf.o
|
||||
|
||||
dag:
|
||||
$(CC) $(CFLAGS) -shared -fPIC src/dag.c \
|
||||
-Lbuild/lib/shared -lglacier_log \
|
||||
-Wl,-rpath,'$$ORIGIN' \
|
||||
-o build/lib/shared/libglacier_dag.so
|
||||
|
||||
install:
|
||||
mkdir -p $(PREFIX)/lib/glacier/
|
||||
install build/lib/shared/libglacier_log.so $(PREFIX)/lib/glacier/ -m 755
|
||||
install build/lib/shared/libglacier_istoreutils.so $(PREFIX)/lib/glacier/ -m 755
|
||||
install build/lib/shared/libglacier_pkg.so $(PREFIX)/lib/glacier -m 755
|
||||
install build/lib/shared/libglacier_dag.so $(PREFIX)/lib/glacier -m 755
|
||||
|
||||
install_static:
|
||||
mkdir -p $(PREFIX)/lib/glacier
|
||||
install build/lib/libglacier.a $(PREFIX)/lib/glacier/ -m 644
|
||||
|
||||
install_test_dir:
|
||||
install build/lib/shared/lg_log.so $(TEST_DIR)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
lg_log.so
|
||||
BIN
build/lib/shared/libglacier_dag.so
Executable file
BIN
build/lib/shared/libglacier_dag.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/lib/shared/libglacier_pkg.so
Executable file
BIN
build/lib/shared/libglacier_pkg.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26
src/dag.c
26
src/dag.c
@@ -3,16 +3,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "graph.h"
|
||||
#include "dag.h"
|
||||
|
||||
graph_t
|
||||
*graph_create(void)
|
||||
*gl_graph_create(void)
|
||||
{
|
||||
return calloc(1, sizeof(graph_t));
|
||||
}
|
||||
|
||||
void
|
||||
graph_free(graph_t *g)
|
||||
gl_graph_free(graph_t *g)
|
||||
{
|
||||
if (!g) { return; }
|
||||
|
||||
@@ -26,7 +26,7 @@ graph_free(graph_t *g)
|
||||
}
|
||||
|
||||
graph_node_t
|
||||
*graph_add_node(graph_t *g, void *data)
|
||||
*gl_graph_add_node(graph_t *g, void *data)
|
||||
{
|
||||
if (!g) { return NULL; }
|
||||
|
||||
@@ -46,7 +46,7 @@ graph_node_t
|
||||
}
|
||||
|
||||
void
|
||||
graph_add_edge(graph_t *g, graph_node_t *from, graph_node_t *to)
|
||||
gl_graph_add_edge(graph_t *g, graph_node_t *from, graph_node_t *to)
|
||||
{
|
||||
if (!g || !from || !to) { return; }
|
||||
graph_node_t **tmp = realloc(from->edges, sizeof(*from->edges) * (from->edge_count + 1));
|
||||
@@ -55,14 +55,14 @@ graph_add_edge(graph_t *g, graph_node_t *from, graph_node_t *to)
|
||||
from->edges[from->edge_count++] = to;
|
||||
}
|
||||
|
||||
static book
|
||||
static bool
|
||||
dfs_cycle(graph_node_t *n)
|
||||
{
|
||||
n->visited = true;
|
||||
n->in_stack = true;
|
||||
|
||||
for (size_t i = 0; i < n->edge_count; i++) {
|
||||
graph_node_t *child = n->edge[i];
|
||||
graph_node_t *child = n->edges[i];
|
||||
if (!child->visited && dfs_cycle(child)) {
|
||||
return true;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ dfs_cycle(graph_node_t *n)
|
||||
}
|
||||
|
||||
bool
|
||||
graph_has_cycle(graph_t *g)
|
||||
gl_graph_has_cycle(graph_t *g)
|
||||
{
|
||||
if (!g) { return false; }
|
||||
for (size_t i = 0; i < g->node_count; i++) {
|
||||
@@ -87,8 +87,8 @@ graph_has_cycle(graph_t *g)
|
||||
if (!g->nodes[i]->visited && dfs_cycle(g->nodes[i])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -101,14 +101,14 @@ dfs_toposort(graph_node_t *n, void **result, size_t *index)
|
||||
}
|
||||
}
|
||||
|
||||
result[(*index)--] = n->data;
|
||||
result[(*index)++] = n->data;
|
||||
}
|
||||
|
||||
void
|
||||
**graph_toposort(graph_t *g, size_t *out_count)
|
||||
**gl_graph_toposort(graph_t *g, size_t *out_count)
|
||||
{
|
||||
if (!g || !out_count) { return NULL; }
|
||||
if (graph_has_cycle(g)) {
|
||||
if (gl_graph_has_cycle(g)) {
|
||||
fprintf(stderr, "Error: dependency cycle detected\n");
|
||||
return NULL;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ void
|
||||
g->nodes[i]->visited = false;
|
||||
}
|
||||
|
||||
ssize_t index = g->node_count - 1;
|
||||
size_t index = 0;
|
||||
for (size_t i = 0; i < g->node_count; i++) {
|
||||
if (!g->nodes[i]->visited) {
|
||||
dfs_toposort(g->nodes[i], order, (size_t *)&index);
|
||||
|
||||
@@ -29,3 +29,7 @@
|
||||
[2025-10-22 15:59:07] [ERR] Failed to install package glibc
|
||||
[2025-10-29 09:19:46] [INFO] Glacier started with PID 12345
|
||||
[2025-10-29 09:19:46] [ERR] Failed to install package glibc
|
||||
[2026-02-04 14:49:07] [INFO] Glacier started with PID 12345
|
||||
[2026-02-04 14:49:07] [ERR] Failed to install package glibc
|
||||
[2026-03-16 13:29:49] [INFO] Glacier started with PID 12345
|
||||
[2026-03-16 13:29:49] [ERR] Failed to install package glibc
|
||||
|
||||
10
src/glacier.xml
Normal file
10
src/glacier.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mine-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-glacier-package">
|
||||
<comment>Glacier Package</comment>
|
||||
<glob pattern="*.gpkg"/>
|
||||
<magic priority="50">
|
||||
<match type="string" offset="0" value="‹"/>
|
||||
</magic>
|
||||
</mime-type>
|
||||
</mine-info>
|
||||
@@ -1,27 +1,35 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/limits.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "istoreutils.h"
|
||||
#include "log.h"
|
||||
#include "pkg.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INDEX,
|
||||
STORE
|
||||
}
|
||||
index_store_t;
|
||||
|
||||
static const dir_t usr_index = { "/glacier/usr/index", 0700 };
|
||||
static const dir_t sys_index = { "/glacier/sys/index", 0700 };
|
||||
|
||||
static const dir_t usr_store = { "/glacier/usr/store", 0700 };
|
||||
static const dir_t sys_store = { "/glacier/sys/store", 0700 };
|
||||
|
||||
static const dir_t usr_links = { "/glacier/usr/links", 0700 };
|
||||
|
||||
bool
|
||||
gl_usr_istore_exists(index_store_t index_or_store, int uid)
|
||||
{
|
||||
@@ -37,7 +45,7 @@ gl_usr_istore_exists(index_store_t index_or_store, int uid)
|
||||
break;
|
||||
default:
|
||||
printf("libglacier: argument index_or_store of function gl_usr_istore_exists must be INDEX or STORE\n");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stat(path, &st) != 0) {
|
||||
@@ -62,7 +70,7 @@ gl_sys_istore_exists(index_store_t index_or_store)
|
||||
break;
|
||||
default:
|
||||
printf("libglacier: argument index_or_store of function gl_sys_istore_exists must be INDEX or STORE\n");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stat(path, &st) != 0) {
|
||||
@@ -72,19 +80,65 @@ gl_sys_istore_exists(index_store_t index_or_store)
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
int
|
||||
gl_init_user(int uid)
|
||||
static void
|
||||
make_index_name(char *buffer, size_t buffersz)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm = localtime(&now);
|
||||
strftime(buffer, buffersz, "index-%m_%d_%Y@%H:%M", tm);
|
||||
}
|
||||
|
||||
static int
|
||||
create_index(const char *ind_path, uid_t uid)
|
||||
{
|
||||
char fname[64];
|
||||
make_index_name(fname, sizeof(fname));
|
||||
|
||||
char full_path[PATH_MAX];
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s", ind_path, fname);
|
||||
|
||||
FILE *f = fopen(full_path, "w");
|
||||
if (!f) { return -1; }
|
||||
fprintf(f, "uid = %d\n", uid);
|
||||
fprintf(f, "listed = 0\n\n");
|
||||
fclose(f);
|
||||
|
||||
if (chown(full_path, uid, (gid_t)-1) != 0) { return -1; }
|
||||
|
||||
char link_path[PATH_MAX];
|
||||
snprintf(link_path, sizeof(link_path), "%s/current", ind_path);
|
||||
unlink(link_path);
|
||||
|
||||
if (symlink(fname, link_path) != 0) { return -1; }
|
||||
if (lchown(link_path, uid, (gid_t)-1) != 0) { return -1; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
gl_init_user(uid_t uid, bool isVerbose)
|
||||
{
|
||||
if (isVerbose) { lg_printf(0, "Checking if UID is within acceptable bounds..."); }
|
||||
if (uid < 1000) {
|
||||
if (isVerbose) {
|
||||
lg_printf(2, "Attempted to create index and store for UID < 1000. Quitting...");
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (isVerbose) { lg_printf(0, "Constructing paths for index and store..."); }
|
||||
|
||||
char ind_path[PATH_MAX];
|
||||
char sto_path[PATH_MAX];
|
||||
char lnk_path[PATH_MAX];
|
||||
|
||||
snprintf(ind_path, sizeof(ind_path), "%s/%d", usr_index.path, uid);
|
||||
snprintf(sto_path, sizeof(sto_path), "%s/%d", usr_store.path, uid);
|
||||
|
||||
snprintf(lnk_path, sizeof(lnk_path), "%s/%d", usr_links.path, uid);
|
||||
|
||||
if (isVerbose) { lg_printf(0, "Paths constructed:\n%s\n%s", ind_path, sto_path); }
|
||||
|
||||
if (isVerbose) { lg_printf(0, "Attempting to create index directory at %s", ind_path); }
|
||||
if (mkdir(ind_path, 0700) == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
@@ -115,6 +169,7 @@ gl_init_user(int uid)
|
||||
}
|
||||
}
|
||||
|
||||
if (isVerbose) { lg_printf(0, "Attempting to create store directory at %s", sto_path); }
|
||||
if (mkdir(sto_path, 0700) == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
@@ -145,6 +200,56 @@ gl_init_user(int uid)
|
||||
}
|
||||
}
|
||||
|
||||
if (isVerbose) { lg_printf(0, "Attempting to create links directory at %s", lnk_path); }
|
||||
if (mkdir(lnk_path, 0700) == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
lg_printf(2, "Cannot create store: permission denied");
|
||||
return 1;
|
||||
break;
|
||||
case EEXIST:
|
||||
lg_printf(2, "Cannot create store: directory already exists");
|
||||
return 1;
|
||||
break;
|
||||
case ENOENT:
|
||||
/* should never happen, but here for completeness */
|
||||
lg_printf(2, "Cannot create store: parent directory does not exist");
|
||||
return 1;
|
||||
break;
|
||||
case ENOSPC:
|
||||
lg_printf(2, "Cannot create store: no space left on device");
|
||||
return 1;
|
||||
break;
|
||||
case EROFS:
|
||||
lg_printf(2, "Cannot create store: read only filesystem");
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
printf("libglacier: mkdir error in function gl_init_user\n");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isVerbose) { lg_printf(0, "Changing ownership of index and store to UID %i", uid); }
|
||||
|
||||
if (chown(sto_path, uid, (gid_t)-1) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chown(ind_path, uid, (gid_t)-1) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chown(lnk_path, uid, (gid_t)-1) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (create_index(ind_path, uid) != 0) {
|
||||
/* No switch for errno. chown() shouldn't fail if mkdir() didn't */
|
||||
lg_printf(2, "Cannot create initial index file");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -162,7 +267,7 @@ trim(char *s)
|
||||
|
||||
size_t len = strlen(s);
|
||||
while (len && isspace((unsigned char)s[len - 1])) {
|
||||
s[len--] = 0;
|
||||
s[--len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,4 +286,714 @@ static char
|
||||
|
||||
int
|
||||
gl_parse_index(struct gindex *idx, FILE *f)
|
||||
{}
|
||||
{
|
||||
idx->uid = -1;
|
||||
idx->listed = -1;
|
||||
idx->entries = NULL;
|
||||
idx->count = 0;
|
||||
|
||||
char line[512];
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
trim(line);
|
||||
if (!line[0] || line[0] == '#') { continue; }
|
||||
|
||||
char *eq = strchr(line, '=');
|
||||
if (eq) {
|
||||
*eq = 0;
|
||||
char *key = line;
|
||||
char *val = eq + 1;
|
||||
trim(key);
|
||||
trim(val);
|
||||
|
||||
if (strcmp(key, "uid") == 0) { idx->uid = atoi(val); }
|
||||
else if (strcmp(key, "listed") == 0) { idx->listed=atoi(val); }
|
||||
continue;
|
||||
}
|
||||
|
||||
char *first = strstr(line, "::");
|
||||
if (!first) { continue; }
|
||||
|
||||
*first = 0;
|
||||
char *repo = line;
|
||||
char *pkg = first + 2;
|
||||
trim(repo);
|
||||
trim(pkg);
|
||||
|
||||
struct gpkg_entry ent;
|
||||
ent.repo = dupstr(repo);
|
||||
ent.pkg = dupstr(pkg);
|
||||
if (!ent.repo || !ent.pkg) { return -1; }
|
||||
|
||||
struct gpkg_entry *tmp =
|
||||
realloc(idx->entries, sizeof(*idx->entries) * (idx->count + 1));
|
||||
if (!tmp) { return -1; }
|
||||
idx->entries = tmp;
|
||||
idx->entries[idx->count++] = ent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
gl_free_index(struct gindex *idx)
|
||||
{
|
||||
for (size_t i = 0; i < idx->count; i++) {
|
||||
free(idx->entries[i].repo);
|
||||
free(idx->entries[i].pkg);
|
||||
}
|
||||
|
||||
free(idx->entries);
|
||||
idx->entries = NULL;
|
||||
idx->count = 0;
|
||||
}
|
||||
/*
|
||||
int
|
||||
gl_rebuild_index(uid_t uid, const char *out_dir)
|
||||
{
|
||||
char store_path[PATH_MAX];
|
||||
snprintf(store_path, sizeof(store_path), "%s/%d", usr_store.path, uid);
|
||||
|
||||
DIR *store_dir = opendir(store_path);
|
||||
if (!store_dir) return -1;
|
||||
|
||||
FILE *out = fopen(out_dir, "w");
|
||||
if (!out) return -1;
|
||||
|
||||
size_t listed = 0;
|
||||
|
||||
struct dirent *repo_ent;
|
||||
while ((repo_ent = readdir(store_dir))) {
|
||||
if (repo_ent->d_name[0] == '.') { continue; }
|
||||
|
||||
char repo_path[PATH_MAX];
|
||||
snprintf(repo_path, sizeof(repo_path), "%s/%s",
|
||||
store_path, repo_ent->d_name);
|
||||
|
||||
struct stat rst;
|
||||
if (stat(repo_path, &rst) != 0 || !S_ISDIR(rst.st_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DIR *repo_dir = opendir(repo_path);
|
||||
if (!repo_dir) continue;
|
||||
|
||||
struct dirent *pkg_ent;
|
||||
while ((pkg_ent = readdir(repo_dir))) {
|
||||
if (pkg_ent->d_name[0] == '.') { continue; }
|
||||
|
||||
char pkg_path[PATH_MAX];
|
||||
snprintf(pkg_path, sizeof(pkg_path), "%s/%s",
|
||||
repo_path, pkg_ent->d_name);
|
||||
|
||||
struct stat pst;
|
||||
if (stat(pkg_path, &pst) != 0 || !S_ISDIR(pst.st_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(out, "%s::%s\n",
|
||||
repo_ent->d_name,
|
||||
pkg_ent->d_name);
|
||||
listed++;
|
||||
}
|
||||
closedir(repo_dir);
|
||||
}
|
||||
|
||||
rewind(out);
|
||||
fprintf(out, "uid = %d\n", uid);
|
||||
fprintf(out, "listed = %zu\n\n", listed);
|
||||
|
||||
closedir(store_dir);
|
||||
fclose(out);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int
|
||||
gl_rebuild_index(uid_t uid, const char *out_dir)
|
||||
{
|
||||
char store_path[PATH_MAX];
|
||||
snprintf(store_path, sizeof(store_path), "%s/%d", usr_store.path, uid);
|
||||
|
||||
DIR *store_dir = opendir(store_path);
|
||||
if (!store_dir) return -1;
|
||||
|
||||
/* Write to a new timestamped index file */
|
||||
char fname[64];
|
||||
make_index_name(fname, sizeof(fname));
|
||||
|
||||
char new_index_path[PATH_MAX];
|
||||
snprintf(new_index_path, sizeof(new_index_path), "%s/%s", out_dir, fname);
|
||||
|
||||
FILE *out = fopen(new_index_path, "w");
|
||||
if (!out) {
|
||||
closedir(store_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t listed = 0;
|
||||
|
||||
struct dirent *repo_ent;
|
||||
while ((repo_ent = readdir(store_dir))) {
|
||||
if (repo_ent->d_name[0] == '.') { continue; }
|
||||
|
||||
char repo_path[PATH_MAX];
|
||||
snprintf(repo_path, sizeof(repo_path), "%s/%s",
|
||||
store_path, repo_ent->d_name);
|
||||
|
||||
struct stat rst;
|
||||
if (stat(repo_path, &rst) != 0 || !S_ISDIR(rst.st_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DIR *repo_dir = opendir(repo_path);
|
||||
if (!repo_dir) continue;
|
||||
|
||||
struct dirent *pkg_ent;
|
||||
while ((pkg_ent = readdir(repo_dir))) {
|
||||
if (pkg_ent->d_name[0] == '.') { continue; }
|
||||
|
||||
char pkg_path[PATH_MAX];
|
||||
snprintf(pkg_path, sizeof(pkg_path), "%s/%s",
|
||||
repo_path, pkg_ent->d_name);
|
||||
|
||||
struct stat pst;
|
||||
if (stat(pkg_path, &pst) != 0 || !S_ISDIR(pst.st_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(out, "%s::%s\n",
|
||||
repo_ent->d_name,
|
||||
pkg_ent->d_name);
|
||||
listed++;
|
||||
}
|
||||
closedir(repo_dir);
|
||||
}
|
||||
closedir(store_dir);
|
||||
fclose(out);
|
||||
|
||||
/* Prepend header by copying through a temp file then renaming over */
|
||||
FILE *tmp_in = fopen(new_index_path, "r");
|
||||
if (!tmp_in) return -1;
|
||||
|
||||
char tmp_path[PATH_MAX];
|
||||
snprintf(tmp_path, sizeof(tmp_path), "%s/.index_tmp_XXXXXX", out_dir);
|
||||
int tmp_fd = mkstemp(tmp_path);
|
||||
if (tmp_fd < 0) { fclose(tmp_in); return -1; }
|
||||
|
||||
FILE *tmp_out = fdopen(tmp_fd, "w");
|
||||
if (!tmp_out) { close(tmp_fd); fclose(tmp_in); return -1; }
|
||||
|
||||
fprintf(tmp_out, "uid = %d\n", uid);
|
||||
fprintf(tmp_out, "listed = %zu\n\n", listed);
|
||||
|
||||
char line[512];
|
||||
while (fgets(line, sizeof(line), tmp_in)) {
|
||||
fputs(line, tmp_out);
|
||||
}
|
||||
fclose(tmp_in);
|
||||
fclose(tmp_out);
|
||||
|
||||
rename(tmp_path, new_index_path);
|
||||
chown(new_index_path, uid, (gid_t)-1);
|
||||
|
||||
/* Update the "current" symlink to point at the new index */
|
||||
char link_path[PATH_MAX];
|
||||
snprintf(link_path, sizeof(link_path), "%s/current", out_dir);
|
||||
unlink(link_path);
|
||||
|
||||
if (symlink(fname, link_path) != 0) { return -1; }
|
||||
lchown(link_path, uid, (gid_t)-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
add_to_archive(struct archive *a, const char *real_path, const char *archive_path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (lstat(real_path, &st) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
struct archive_entry *entry = archive_entry_new();
|
||||
archive_entry_set_pathname(entry, archive_path);
|
||||
archive_entry_set_filetype(entry, AE_IFDIR);
|
||||
archive_entry_set_perm(entry, st.st_mode & 0777);
|
||||
|
||||
if (archive_write_header(a, entry) != ARCHIVE_OK) {
|
||||
archive_entry_free(entry);
|
||||
return -1;
|
||||
}
|
||||
|
||||
archive_entry_free(entry);
|
||||
|
||||
DIR *dir = opendir(real_path); /* NEW */
|
||||
if (!dir) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(dir))) { /* NEW */
|
||||
if (strcmp(ent->d_name, ".") == 0 ||
|
||||
strcmp(ent->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
char child_real[PATH_MAX]; /* NEW */
|
||||
char child_arch[PATH_MAX]; /* NEW */
|
||||
|
||||
snprintf(child_real, sizeof(child_real),
|
||||
"%s/%s", real_path, ent->d_name);
|
||||
|
||||
snprintf(child_arch, sizeof(child_arch),
|
||||
"%s/%s", archive_path, ent->d_name);
|
||||
|
||||
if (add_to_archive(a, child_real, child_arch) != 0) {
|
||||
closedir(dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* existing file handling logic continues below */
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
|
||||
int fd = open(real_path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct archive_entry *entry = archive_entry_new();
|
||||
archive_entry_set_pathname(entry, archive_path);
|
||||
archive_entry_set_size(entry, st.st_size);
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
archive_entry_set_perm(entry, st.st_mode & 0777);
|
||||
|
||||
if (archive_write_header(a, entry) != ARCHIVE_OK) {
|
||||
archive_entry_free(entry);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[8192];
|
||||
ssize_t n;
|
||||
|
||||
while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
if (archive_write_data(a, buf, (size_t)n) < 0) {
|
||||
archive_entry_free(entry);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
archive_entry_free(entry);
|
||||
close(fd);
|
||||
|
||||
if (n < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0; /* NEW: ignore other file types */
|
||||
}
|
||||
|
||||
gl_backup_status_t
|
||||
gl_backup_istore(const char *tar_path,
|
||||
const char *glacier_root,
|
||||
const char *uid)
|
||||
{
|
||||
struct archive *a = archive_write_new();
|
||||
if (!a) { return GL_BACKUP_ERR_ALLOC; }
|
||||
|
||||
if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) {
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_OPEN;
|
||||
}
|
||||
|
||||
if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) {
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_OPEN;
|
||||
}
|
||||
|
||||
if (archive_write_open_filename(a, tar_path) != ARCHIVE_OK) {
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_OPEN;
|
||||
}
|
||||
|
||||
char index_path[1024];
|
||||
char store_path[1024];
|
||||
char links_path[1024];
|
||||
|
||||
char arch_index[512];
|
||||
char arch_store[512];
|
||||
char arch_links[512];
|
||||
|
||||
snprintf(index_path, sizeof(index_path), "%s/index/%s", glacier_root, uid);
|
||||
snprintf(store_path, sizeof(store_path), "%s/store/%s", glacier_root, uid);
|
||||
snprintf(links_path, sizeof(links_path), "%s/links/%s", glacier_root, uid);
|
||||
|
||||
snprintf(arch_index, sizeof(arch_index), "%s/index", uid);
|
||||
snprintf(arch_store, sizeof(arch_store), "%s/store", uid);
|
||||
snprintf(arch_links, sizeof(arch_links), "%s/links", uid);
|
||||
|
||||
if (add_to_archive(a, index_path, arch_index) != 0) {
|
||||
archive_write_close(a);
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_ADD_INDEX;
|
||||
}
|
||||
|
||||
if (add_to_archive(a, store_path, arch_store) != 0) {
|
||||
archive_write_close(a);
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_ADD_STORE;
|
||||
}
|
||||
|
||||
if (add_to_archive(a, links_path, arch_links) != 0) {
|
||||
archive_write_close(a);
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_ADD_LINKS;
|
||||
}
|
||||
|
||||
if (archive_write_close(a) != ARCHIVE_OK) {
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_ERR_CLOSE;
|
||||
}
|
||||
|
||||
archive_write_free(a);
|
||||
return GL_BACKUP_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
gl_mkdirp(const char *path, mode_t mode)
|
||||
{
|
||||
char tmp[PATH_MAX];
|
||||
strncpy(tmp, path, sizeof(tmp));
|
||||
tmp[sizeof(tmp) - 1] = '\0';
|
||||
|
||||
for (char *p = tmp + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
if (mkdir(tmp, mode) == -1 && errno != EEXIST) {
|
||||
return -1;
|
||||
}
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (mkdir(tmp, mode) == -1 && errno != EEXIST) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gl_link_pkg(const char *pkg_store_final, uid_t uid)
|
||||
{
|
||||
char links_base[PATH_MAX];
|
||||
snprintf(links_base, sizeof(links_base), "%s/%d", usr_links.path, uid);
|
||||
|
||||
size_t strip_len = strlen(pkg_store_final);
|
||||
|
||||
/* use a stack-based queue to walk the tree without recursion */
|
||||
char *stack[4096];
|
||||
int top = 0;
|
||||
|
||||
stack[top++] = strdup(pkg_store_final);
|
||||
|
||||
while (top > 0) {
|
||||
char *current = stack[--top];
|
||||
|
||||
DIR *dir = opendir(current);
|
||||
if (!dir) {
|
||||
free(current);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(dir))) {
|
||||
if (ent->d_name[0] == '.') { continue; }
|
||||
|
||||
char full_path[PATH_MAX];
|
||||
snprintf(full_path, sizeof(full_path), "%s/%s",
|
||||
current, ent->d_name);
|
||||
|
||||
struct stat st;
|
||||
if (lstat(full_path, &st) != 0) { continue; }
|
||||
|
||||
/* relative path inside the package, e.g. usr/bin/kilo */
|
||||
const char *rel = full_path + strip_len;
|
||||
if (rel[0] == '/') { rel++; }
|
||||
|
||||
/* strip leading usr/ so bin/kilo lands at links/1000/bin/kilo */
|
||||
if (strncmp(rel, "usr/", 4) == 0) { rel += 4; }
|
||||
|
||||
char link_path[PATH_MAX];
|
||||
snprintf(link_path, sizeof(link_path), "%s/%s",
|
||||
links_base, rel);
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* create the directory in the links tree */
|
||||
gl_mkdirp(link_path, 0700);
|
||||
|
||||
/* push onto stack to recurse into */
|
||||
if (top < 4096) {
|
||||
stack[top++] = strdup(full_path);
|
||||
}
|
||||
} else if (S_ISREG(st.st_mode)) {
|
||||
/* create parent dirs in links tree */
|
||||
char parent[PATH_MAX];
|
||||
strncpy(parent, link_path, sizeof(parent));
|
||||
char *slash = strrchr(parent, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
gl_mkdirp(parent, 0700);
|
||||
}
|
||||
|
||||
/* remove existing symlink if present */
|
||||
unlink(link_path);
|
||||
|
||||
/* symlink store path -> links tree */
|
||||
if (symlink(full_path, link_path) != 0) {
|
||||
closedir(dir);
|
||||
free(current);
|
||||
while (top > 0) { free(stack[--top]); }
|
||||
return -1;
|
||||
}
|
||||
|
||||
lchown(link_path, uid, (gid_t)-1);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
free(current);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gl_install_status_t
|
||||
gl_install_pkg(const char *gpkg_path, uid_t uid)
|
||||
{
|
||||
/* The archive is opened and the manifest is parsed here */
|
||||
struct archive *a = archive_read_new();
|
||||
archive_read_support_filter_gzip(a);
|
||||
archive_read_support_format_tar(a);
|
||||
|
||||
if (archive_read_open_filename(a, gpkg_path, 10240) != ARCHIVE_OK) {
|
||||
archive_read_free(a);
|
||||
return GL_INSTALL_ERR_OPEN;
|
||||
}
|
||||
|
||||
struct archive_entry *entry;
|
||||
gl_pkg_t pkg = {0};
|
||||
bool manifest_found = false;
|
||||
|
||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
|
||||
const char *path = archive_entry_pathname(entry);
|
||||
|
||||
if (strstr(path, "manifest.gpm.cfg")) {
|
||||
char tmp_manifest[PATH_MAX];
|
||||
strncpy(tmp_manifest, "/tmp/gpkg_manifest_XXXXXX",
|
||||
sizeof(tmp_manifest));
|
||||
|
||||
int fd = mkstemp(tmp_manifest);
|
||||
if (fd < 0) {
|
||||
archive_read_free(a);
|
||||
return GL_INSTALL_ERR_MANIFEST;
|
||||
}
|
||||
|
||||
char buffer[8192];
|
||||
ssize_t n;
|
||||
|
||||
while ((n = archive_read_data(a, buffer, sizeof(buffer))) > 0) {
|
||||
ssize_t written = write(fd, buffer, (size_t)n);
|
||||
if (written < 0 || written != n) {
|
||||
close(fd);
|
||||
unlink(tmp_manifest);
|
||||
archive_read_free(a);
|
||||
return GL_INSTALL_ERR_MANIFEST;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
if (gl_gpm2gpkg(tmp_manifest, &pkg) != 0) {
|
||||
unlink(tmp_manifest);
|
||||
archive_read_free(a);
|
||||
return GL_INSTALL_ERR_MANIFEST;
|
||||
}
|
||||
|
||||
unlink(tmp_manifest);
|
||||
manifest_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
archive_read_data_skip(a);
|
||||
}
|
||||
|
||||
archive_read_free(a);
|
||||
|
||||
if (!manifest_found) {
|
||||
return GL_INSTALL_ERR_MANIFEST;
|
||||
}
|
||||
|
||||
char pkg_store_base[PATH_MAX];
|
||||
char pkg_store_final[PATH_MAX];
|
||||
|
||||
/* construct the directory for the package in the store */
|
||||
snprintf(pkg_store_base, sizeof(pkg_store_base),
|
||||
"%s/%d/%s/%s", usr_store.path, uid, pkg.pkg_repo, pkg.pkg_name);
|
||||
|
||||
snprintf(pkg_store_final, sizeof(pkg_store_final),
|
||||
"%s/%s-%d.%d.%d", pkg_store_base, pkg.pkg_name,
|
||||
pkg.pkg_ver.maj, pkg.pkg_ver.min, pkg.pkg_ver.pat);
|
||||
|
||||
if (gl_mkdirp(pkg_store_base, 0700) == -1) {
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
|
||||
if (mkdir(pkg_store_final, 0700) == -1) {
|
||||
if (errno == EEXIST) {
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_ALREADY_INSTALLED;
|
||||
}
|
||||
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
|
||||
/* now the archive must be reopened in order to extract package files */
|
||||
struct archive *a2 = archive_read_new();
|
||||
archive_read_support_filter_gzip(a2);
|
||||
archive_read_support_format_tar(a2);
|
||||
|
||||
if (archive_read_open_filename(a2, gpkg_path, 10240) != ARCHIVE_OK) {
|
||||
archive_read_free(a2);
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
|
||||
char strip_prefix[PATH_MAX];
|
||||
snprintf(strip_prefix, sizeof(strip_prefix),
|
||||
"%s-%d.%d.%d/files/", pkg.pkg_name,
|
||||
pkg.pkg_ver.maj, pkg.pkg_ver.min, pkg.pkg_ver.pat);
|
||||
|
||||
while (archive_read_next_header(a2, &entry) == ARCHIVE_OK) {
|
||||
const char *entry_path = archive_entry_pathname(entry);
|
||||
|
||||
if (strncmp(entry_path, strip_prefix, strlen(strip_prefix)) != 0) {
|
||||
archive_read_data_skip(a2);
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *rel_path = entry_path + strlen(strip_prefix);
|
||||
if (rel_path[0] == '\0') {
|
||||
archive_read_data_skip(a2);
|
||||
continue;
|
||||
}
|
||||
|
||||
char dest_path[PATH_MAX];
|
||||
snprintf(dest_path, sizeof(dest_path), "%s/%s",
|
||||
pkg_store_final, rel_path);
|
||||
|
||||
if (archive_entry_filetype(entry) == AE_IFDIR) {
|
||||
if (mkdir(dest_path, archive_entry_perm(entry)) == -1
|
||||
&& errno != EEXIST) {
|
||||
archive_read_free(a2);
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
}
|
||||
else if (archive_entry_filetype(entry) == AE_IFREG) {
|
||||
char parent[PATH_MAX];
|
||||
strncpy(parent, dest_path, sizeof(parent));
|
||||
char *slash = strrchr(parent, '/');
|
||||
if (slash) {
|
||||
*slash = '\0';
|
||||
gl_mkdirp(parent, 0700);
|
||||
}
|
||||
|
||||
int fd = open(dest_path, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
archive_entry_perm(entry));
|
||||
|
||||
if (fd < 0) {
|
||||
archive_read_free(a2);
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
|
||||
char buffer[8192];
|
||||
ssize_t n;
|
||||
while ((n = archive_read_data(a2, buffer, sizeof(buffer))) > 0) {
|
||||
ssize_t written = write(fd, buffer, (size_t)n);
|
||||
if (written < 0 || written != n) {
|
||||
close(fd);
|
||||
archive_read_free(a2);
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
archive_read_free(a2);
|
||||
|
||||
/* now the index will be updated */
|
||||
|
||||
/* now the index will be updated */
|
||||
char index_dir[PATH_MAX];
|
||||
snprintf(index_dir, sizeof(index_dir),
|
||||
"%s/%d", usr_index.path, uid);
|
||||
|
||||
/* Resolve "current" symlink to find the actual index file to append to */
|
||||
char current_link[PATH_MAX];
|
||||
snprintf(current_link, sizeof(current_link), "%s/current", index_dir);
|
||||
|
||||
char current_target[PATH_MAX];
|
||||
ssize_t len = readlink(current_link, current_target, sizeof(current_target) - 1);
|
||||
if (len < 0) {
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_INDEX;
|
||||
}
|
||||
current_target[len] = '\0';
|
||||
|
||||
char index_path[PATH_MAX];
|
||||
snprintf(index_path, sizeof(index_path), "%s/%s", index_dir, current_target);
|
||||
|
||||
FILE *idx = fopen(index_path, "a");
|
||||
if (!idx) {
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_INDEX;
|
||||
}
|
||||
|
||||
fprintf(idx, "%s::%s\n", pkg.pkg_repo, pkg.pkg_name);
|
||||
fclose(idx);
|
||||
|
||||
if (gl_rebuild_index(uid, index_dir) != 0) {
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_INDEX;
|
||||
}
|
||||
|
||||
if (gl_link_pkg(pkg_store_final, uid) != 0) {
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_ERR_EXTRACT;
|
||||
}
|
||||
|
||||
gl_free_pkg(&pkg);
|
||||
return GL_INSTALL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
71
src/istoreutils.h
Normal file
71
src/istoreutils.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef ISTOREUTILS_H_
|
||||
#define ISTOREUTILS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum {
|
||||
INDEX,
|
||||
STORE
|
||||
}
|
||||
index_store_t;
|
||||
|
||||
typedef enum {
|
||||
GL_BACKUP_OK = 0,
|
||||
GL_BACKUP_ERR_ALLOC = 1,
|
||||
GL_BACKUP_ERR_OPEN = 2,
|
||||
GL_BACKUP_ERR_ADD_INDEX = 3,
|
||||
GL_BACKUP_ERR_ADD_STORE = 4,
|
||||
GL_BACKUP_ERR_ADD_LINKS = 5,
|
||||
GL_BACKUP_ERR_CLOSE = 6
|
||||
}
|
||||
gl_backup_status_t;
|
||||
|
||||
/*
|
||||
* GL_INSTALL_OK: installation successful
|
||||
* GL_INSTALL_ERR_OPEN: unable to open .gpkg file
|
||||
* GL_INSTALL_ERR_MANIFEST: manifest is missing or unparseable
|
||||
* GL_INSTALL_ERR_EXTRACT: unable to extract files
|
||||
* GL_INSTALL_ERR_INDEX: unable to update index
|
||||
* GL_INSTALL_ERR_ALREADY_INSTALLED: package already installed
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
GL_INSTALL_OK = 0,
|
||||
GL_INSTALL_ERR_OPEN = 1,
|
||||
GL_INSTALL_ERR_MANIFEST = 2,
|
||||
GL_INSTALL_ERR_EXTRACT = 3,
|
||||
GL_INSTALL_ERR_INDEX = 4,
|
||||
GL_INSTALL_ERR_ALREADY_INSTALLED = 5,
|
||||
}
|
||||
gl_install_status_t;
|
||||
|
||||
struct gpkg_entry {
|
||||
char *repo;
|
||||
char *pkg;
|
||||
};
|
||||
|
||||
struct gindex {
|
||||
int uid;
|
||||
int listed;
|
||||
struct gpkg_entry *entries;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
bool gl_usr_istore_exists(index_store_t index_or_store, int uid);
|
||||
bool gl_sys_istore_exists(index_store_t index_or_store);
|
||||
|
||||
int gl_init_user(uid_t uid, bool isVerbose);
|
||||
|
||||
int gl_parse_index(struct gindex *idx, FILE *f);
|
||||
void gl_free_index(struct gindex *idx);
|
||||
|
||||
int gl_rebuild_index(uid_t uid, const char *out_dir);
|
||||
|
||||
gl_backup_status_t gl_backup_istore(const char *tar_path, const char *glacier_root,
|
||||
const char *uid);
|
||||
|
||||
gl_install_status_t gl_install_pkg(const char *gpkg_path, uid_t uid);
|
||||
|
||||
#endif
|
||||
@@ -183,12 +183,13 @@ lg_gstore_help(int argc, char *argv[])
|
||||
(void)argc;
|
||||
|
||||
printf("%s: Manage Glacier packages indexes/stores\n", argv[0]);
|
||||
printf("usage: %s [-hv] [-snx UID] [-V]\n", argv[0]);
|
||||
printf("usage: %s [-hv] [-snbx UID] [-V]\n", argv[0]);
|
||||
printf("\n");
|
||||
printf("%-25s %s\n", "{-h --help}", "Show this message");
|
||||
printf("%-25s %s\n", "{-v --version}", "Show the current version");
|
||||
printf("%-25s %s\n", "{-s --sync} UID", "Sync UID's store with their index");
|
||||
printf("%-25s %s\n", "{-n --new} UID", "Create new store and index for UID");
|
||||
printf("%-25s %s\n", "{-b --backup} UID OUTFILE", "Create tar backup of UID's index and store at OUTFILE");
|
||||
printf("%-25s %s\n", "{-x --delete} UID", "Delete UID's store and index");
|
||||
printf("%-25s %s\n", "{-V --verbose}", "Log events more verbosely");
|
||||
printf("\n");
|
||||
|
||||
130
src/pkg.c
130
src/pkg.c
@@ -13,76 +13,24 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* semver_t
|
||||
* DESCRIPTION: defines the struct for storing semantic versioning numbers
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int maj;
|
||||
int min;
|
||||
int pat;
|
||||
char *tag;
|
||||
}
|
||||
semver_t;
|
||||
|
||||
/*
|
||||
* dep_t
|
||||
* DESCRIPTION: defines the struct for storing dependent packages
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *dep_name;
|
||||
semver_t dep_ver;
|
||||
}
|
||||
dep_t;
|
||||
|
||||
/*
|
||||
* conf_t
|
||||
* DESCRIPTION: defines the struct for storing conflicting packages
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *conf_name;
|
||||
semver_t conf_ver;
|
||||
}
|
||||
conf_t;
|
||||
|
||||
/*
|
||||
* gl_pkg_t
|
||||
* DESCRIPTION: defines the struct for storing packages in the gpkg format
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *pkg_name;
|
||||
semver_t pkg_ver;
|
||||
|
||||
char *pkg_desc;
|
||||
char *pkg_maint;
|
||||
char *pkg_copyright;
|
||||
|
||||
dep_t *pkg_dependencies;
|
||||
conf_t *pkg_conflicts;
|
||||
}
|
||||
gl_pkg_t;
|
||||
#include "pkg.h"
|
||||
|
||||
/* directory definitions */
|
||||
static const dir_t gl_root = { "/glacier", 0750 };
|
||||
const dir_t gl_root = { "/glacier", 0750 };
|
||||
|
||||
static const dir_t gl_usr = { "/glacier/usr", 0700 };
|
||||
static const dir_t gl_usr_index = { "/glacier/usr/index", 0700 };
|
||||
static const dir_t gl_usr_store = { "/glacier/usr/store", 0700 };
|
||||
const dir_t gl_usr = { "/glacier/usr", 0700 };
|
||||
const dir_t gl_usr_index = { "/glacier/usr/index", 0700 };
|
||||
const dir_t gl_usr_store = { "/glacier/usr/store", 0700 };
|
||||
|
||||
static const dir_t gl_sys = { "/glacier/sys", 0700 };
|
||||
static const dir_t gl_sys_index = { "/glacier/sys/index", 0700 };
|
||||
static const dir_t gl_sys_store = { "/glacier/sys/store", 0700 };
|
||||
const dir_t gl_sys = { "/glacier/sys", 0700 };
|
||||
const dir_t gl_sys_index = { "/glacier/sys/index", 0700 };
|
||||
const dir_t gl_sys_store = { "/glacier/sys/store", 0700 };
|
||||
|
||||
/* null dependencies/conflicts for error throwing */
|
||||
static dep_t null_dep = { "null", {-1, -1, -1, NULL} };
|
||||
static conf_t null_conf = { "null", {-1, -1, -1, NULL} };
|
||||
dep_t null_dep = { "null", {-1, -1, -1, NULL} };
|
||||
conf_t null_conf = { "null", {-1, -1, -1, NULL} };
|
||||
|
||||
static char
|
||||
char
|
||||
*join_with_cwd(const char *path)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
@@ -150,6 +98,7 @@ gl_pkg_t empty = {
|
||||
"Null package for internal use. Returned upon an error.",
|
||||
"null@null.null",
|
||||
"null",
|
||||
"null",
|
||||
&null_dep,
|
||||
&null_conf
|
||||
};
|
||||
@@ -167,7 +116,7 @@ gl_mkdir(dir_t *dir)
|
||||
}
|
||||
|
||||
gl_pkg_t
|
||||
*gl_spawn_pkg(char *name, semver_t *ver, char *desc, char *maint, char *copy, dep_t *dep, conf_t *conf)
|
||||
*gl_spawn_pkg(char *name, semver_t *ver, char *desc, char *maint, char *copy, char *repo, dep_t *dep, conf_t *conf)
|
||||
{
|
||||
gl_pkg_t *new_pkg = malloc(sizeof(gl_pkg_t));
|
||||
if (!new_pkg) { return NULL; }
|
||||
@@ -177,6 +126,7 @@ gl_pkg_t
|
||||
new_pkg -> pkg_desc = desc;
|
||||
new_pkg -> pkg_maint = maint;
|
||||
new_pkg -> pkg_copyright = copy;
|
||||
new_pkg -> pkg_repo = repo;
|
||||
new_pkg -> pkg_dependencies = dep;
|
||||
new_pkg -> pkg_conflicts = conf;
|
||||
|
||||
@@ -200,15 +150,16 @@ gl_gpm2gpkg(const char *filename, gl_pkg_t *pkg)
|
||||
if (config_lookup_string(&cfg, "PKG_DESC", &tmp_str)) { pkg->pkg_desc = strdup(tmp_str); }
|
||||
if (config_lookup_string(&cfg, "PKG_MAINT", &tmp_str)) { pkg->pkg_maint = strdup(tmp_str); }
|
||||
if (config_lookup_string(&cfg, "PKG_COPYRIGHT", &tmp_str)) { pkg->pkg_copyright = strdup(tmp_str); }
|
||||
if (config_lookup_string(&cfg, "PKG_REPO", &tmp_str)) { pkg->pkg_repo = strdup(tmp_str); }
|
||||
if (config_lookup_string(&cfg, "PKG_VER", &tmp_str)) { pkg->pkg_ver = gl_parse_semver(tmp_str); }
|
||||
|
||||
deps = config_lookup(&cfg, "PKG_DEPS");
|
||||
if (deps && config_setting_is_list(deps)) {
|
||||
int count = config_setting_length(deps);
|
||||
pkg->pkg_dependencies = calloc(count + 1, sizeof(dep_t));
|
||||
pkg->pkg_dependencies = calloc((size_t)(count + 1), sizeof(dep_t));
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
config_setting_t *d = config_setting_get_elem(deps, i);
|
||||
config_setting_t *d = config_setting_get_elem(deps, (unsigned int)i);
|
||||
const char *dep_name = NULL;
|
||||
const char *dep_ver = NULL;
|
||||
|
||||
@@ -223,10 +174,10 @@ gl_gpm2gpkg(const char *filename, gl_pkg_t *pkg)
|
||||
confs = config_lookup(&cfg, "PKG_CONFS");
|
||||
if (confs && config_setting_is_list(confs)) {
|
||||
int count = config_setting_length(confs);
|
||||
pkg->pkg_conflicts = calloc(count + 1, sizeof(conf_t));
|
||||
pkg->pkg_conflicts = calloc((size_t)(count + 1), sizeof(conf_t));
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
config_setting_t *c = config_setting_get_elem(confs, i);
|
||||
config_setting_t *c = config_setting_get_elem(confs, (unsigned int)i);
|
||||
const char *conf_name = NULL;
|
||||
const char *conf_ver = NULL;
|
||||
|
||||
@@ -295,7 +246,7 @@ void
|
||||
gl_free_dir(dir_t *dir)
|
||||
{
|
||||
if (dir && dir->path) {
|
||||
free(dir->path);
|
||||
free((char *)dir->path);
|
||||
dir->path = NULL;
|
||||
}
|
||||
}
|
||||
@@ -309,6 +260,7 @@ gl_free_pkg(gl_pkg_t *pkg)
|
||||
free(pkg->pkg_desc);
|
||||
free(pkg->pkg_maint);
|
||||
free(pkg->pkg_copyright);
|
||||
free(pkg->pkg_repo);
|
||||
|
||||
gl_free_semver(&pkg->pkg_ver);
|
||||
|
||||
@@ -394,43 +346,3 @@ gl_show_pkg_props(const gl_pkg_t *pkg)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
semver_t foo_v = gl_pkgver(1, 1, 1);
|
||||
dep_t dep_empty = {"empty", foo_v};
|
||||
conf_t conf_empty = {"empty", foo_v};
|
||||
gl_pkg_t *foo = gl_spawn_pkg(
|
||||
"foo",
|
||||
&foo_v,
|
||||
"example pkg",
|
||||
"liamwaldron@everestlinux.org",
|
||||
"GPL3",
|
||||
&dep_empty,
|
||||
&conf_empty
|
||||
);
|
||||
|
||||
gl_show_pkg_props(foo);
|
||||
gl_show_pkg_props(&empty);
|
||||
|
||||
gl_pkg_t bar = {0};
|
||||
|
||||
char *bar_path = join_with_cwd("bar.gpm.cfg");
|
||||
if (!bar_path) { return 1; }
|
||||
|
||||
if (gl_gpm2gpkg(bar_path, &bar) == 0) { gl_show_pkg_props(&bar); }
|
||||
else { return 99; }
|
||||
|
||||
free(bar_path);
|
||||
|
||||
if (gl_prepare_pkgdir(foo, false) == 0) {
|
||||
printf("Package prepared\n");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
gl_free_pkg(foo);
|
||||
gl_free_pkg(&bar);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ typedef struct {
|
||||
char *pkg_desc;
|
||||
char *pkg_maint;
|
||||
char *pkg_copyright;
|
||||
char *pkg_repo;
|
||||
dep_t *pkg_dependencies;
|
||||
conf_t *pkg_conflicts;
|
||||
}
|
||||
@@ -62,8 +63,8 @@ void gl_free_semver(semver_t *v);
|
||||
|
||||
gl_pkg_t *gl_spawn_pkg(
|
||||
char *name, semver_t *ver, char *desc,
|
||||
char *maint, char *copy, dep_t *dep,
|
||||
conf_t conf
|
||||
char *maint, char *copy, char *repo,
|
||||
dep_t *dep, conf_t *conf
|
||||
);
|
||||
|
||||
void gl_show_pkg_props(const gl_pkg_t *pkg);
|
||||
@@ -77,7 +78,7 @@ dir_t gl_return_dir_and_ver(const dir_t *base, gl_pkg_t *pkg, mode_t mode);
|
||||
void gl_free_path(char *path);
|
||||
void gl_free_dir(dir_t *dir);
|
||||
|
||||
int gl_gpm2gpkg(const char *filename, gl_pkg_t pkg);
|
||||
int gl_gpm2gpkg(const char *filename, gl_pkg_t *pkg);
|
||||
int gl_prepare_pkgdir(gl_pkg_t *pkg, bool is_syspkg);
|
||||
char *join_with_cwd(const char *path);
|
||||
|
||||
|
||||
17
src/test_backup.c
Normal file
17
src/test_backup.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "istoreutils.h"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
gl_backup_status_t status = gl_backup_istore("/tmp/backup.tar",
|
||||
"/home/lw/Projects/glacier-ng/tree/glacier",
|
||||
"1000"
|
||||
);
|
||||
|
||||
if (status != GL_BACKUP_OK) {
|
||||
printf("backup failed: %d\n", status);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user