3/18: Functional package installation backend

This commit is contained in:
2026-03-18 09:57:09 -04:00
parent e79c96a987
commit 6819fe7c69
24 changed files with 1011 additions and 145 deletions

View File

@@ -1,8 +1,27 @@
include config.mk 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" @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: prepare:
mkdir -p build mkdir -p build
mkdir -p build/lib mkdir -p build/lib
@@ -21,20 +40,37 @@ log_test:
rt: rt:
$(CC) $(CFLAGS) src/runtime.c -c -o build/lib/tmp/runtime.o $(CC) $(CFLAGS) src/runtime.c -c -o build/lib/tmp/runtime.o
istoreutils: istoreutils: pkg
$(CC) $(CFLAGS) -shared -fPIC src/istoreutils.c \ $(CC) $(CFLAGS) -shared -fPIC src/istoreutils.c \
-Lbuild/lib/shared -lglacier_log \ -Lbuild/lib/shared -lglacier_log -lglacier_pkg -larchive \
-Wl,-rpath,'$$ORIGIN' \ -Wl,-rpath,'$$ORIGIN' \
-o build/lib/shared/libglacier_istoreutils.so -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: make_conf:
$(CC) $(CFLAGS) src/make_conf.c -c -o build/lib/tmp/make_conf.o $(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: install:
mkdir -p $(PREFIX)/lib/glacier/ mkdir -p $(PREFIX)/lib/glacier/
install build/lib/shared/libglacier_log.so $(PREFIX)/lib/glacier/ -m 755 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_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_test_dir:
install build/lib/shared/lg_log.so $(TEST_DIR) install build/lib/shared/lg_log.so $(TEST_DIR)

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
lg_log.so

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,16 +3,16 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "graph.h" #include "dag.h"
graph_t graph_t
*graph_create(void) *gl_graph_create(void)
{ {
return calloc(1, sizeof(graph_t)); return calloc(1, sizeof(graph_t));
} }
void void
graph_free(graph_t *g) gl_graph_free(graph_t *g)
{ {
if (!g) { return; } if (!g) { return; }
@@ -26,7 +26,7 @@ graph_free(graph_t *g)
} }
graph_node_t graph_node_t
*graph_add_node(graph_t *g, void *data) *gl_graph_add_node(graph_t *g, void *data)
{ {
if (!g) { return NULL; } if (!g) { return NULL; }
@@ -46,7 +46,7 @@ graph_node_t
} }
void 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; } if (!g || !from || !to) { return; }
graph_node_t **tmp = realloc(from->edges, sizeof(*from->edges) * (from->edge_count + 1)); 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; from->edges[from->edge_count++] = to;
} }
static book static bool
dfs_cycle(graph_node_t *n) dfs_cycle(graph_node_t *n)
{ {
n->visited = true; n->visited = true;
n->in_stack = true; n->in_stack = true;
for (size_t i = 0; i < n->edge_count; i++) { 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)) { if (!child->visited && dfs_cycle(child)) {
return true; return true;
} }
@@ -76,7 +76,7 @@ dfs_cycle(graph_node_t *n)
} }
bool bool
graph_has_cycle(graph_t *g) gl_graph_has_cycle(graph_t *g)
{ {
if (!g) { return false; } if (!g) { return false; }
for (size_t i = 0; i < g->node_count; i++) { 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])) { if (!g->nodes[i]->visited && dfs_cycle(g->nodes[i])) {
return true; return true;
} }
return false;
} }
return false;
} }
static void 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 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 (!g || !out_count) { return NULL; }
if (graph_has_cycle(g)) { if (gl_graph_has_cycle(g)) {
fprintf(stderr, "Error: dependency cycle detected\n"); fprintf(stderr, "Error: dependency cycle detected\n");
return NULL; return NULL;
} }
@@ -121,7 +121,7 @@ void
g->nodes[i]->visited = false; 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++) { for (size_t i = 0; i < g->node_count; i++) {
if (!g->nodes[i]->visited) { if (!g->nodes[i]->visited) {
dfs_toposort(g->nodes[i], order, (size_t *)&index); dfs_toposort(g->nodes[i], order, (size_t *)&index);

View File

@@ -29,3 +29,7 @@
[2025-10-22 15:59:07] [ERR] Failed to install package glibc [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] [INFO] Glacier started with PID 12345
[2025-10-29 09:19:46] [ERR] Failed to install package glibc [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
View 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="&#x1f;&#x8b;"/>
</magic>
</mime-type>
</mine-info>

View File

@@ -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 <errno.h>
#include <fcntl.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "common.h" #include "common.h"
#include "istoreutils.h"
#include "log.h" #include "log.h"
#include "pkg.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 usr_index = { "/glacier/usr/index", 0700 };
static const dir_t sys_index = { "/glacier/sys/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 usr_store = { "/glacier/usr/store", 0700 };
static const dir_t sys_store = { "/glacier/sys/store", 0700 }; static const dir_t sys_store = { "/glacier/sys/store", 0700 };
static const dir_t usr_links = { "/glacier/usr/links", 0700 };
bool bool
gl_usr_istore_exists(index_store_t index_or_store, int uid) 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; break;
default: default:
printf("libglacier: argument index_or_store of function gl_usr_istore_exists must be INDEX or STORE\n"); 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) { if (stat(path, &st) != 0) {
@@ -62,7 +70,7 @@ gl_sys_istore_exists(index_store_t index_or_store)
break; break;
default: default:
printf("libglacier: argument index_or_store of function gl_sys_istore_exists must be INDEX or STORE\n"); 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) { 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); return S_ISDIR(st.st_mode);
} }
int static void
gl_init_user(int uid) 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 (uid < 1000) {
if (isVerbose) {
lg_printf(2, "Attempted to create index and store for UID < 1000. Quitting...");
}
return 2; return 2;
} }
if (isVerbose) { lg_printf(0, "Constructing paths for index and store..."); }
char ind_path[PATH_MAX]; char ind_path[PATH_MAX];
char sto_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(ind_path, sizeof(ind_path), "%s/%d", usr_index.path, uid);
snprintf(sto_path, sizeof(sto_path), "%s/%d", usr_store.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) { if (mkdir(ind_path, 0700) == -1) {
switch (errno) { switch (errno) {
case EACCES: 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) { if (mkdir(sto_path, 0700) == -1) {
switch (errno) { switch (errno) {
case EACCES: 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; return 0;
} }
@@ -162,7 +267,7 @@ trim(char *s)
size_t len = strlen(s); size_t len = strlen(s);
while (len && isspace((unsigned char)s[len - 1])) { while (len && isspace((unsigned char)s[len - 1])) {
s[len--] = 0; s[--len] = 0;
} }
} }
@@ -181,4 +286,714 @@ static char
int int
gl_parse_index(struct gindex *idx, FILE *f) 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
View 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

View File

@@ -183,12 +183,13 @@ lg_gstore_help(int argc, char *argv[])
(void)argc; (void)argc;
printf("%s: Manage Glacier packages indexes/stores\n", argv[0]); 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("\n");
printf("%-25s %s\n", "{-h --help}", "Show this message"); printf("%-25s %s\n", "{-h --help}", "Show this message");
printf("%-25s %s\n", "{-v --version}", "Show the current version"); 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", "{-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", "{-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", "{-x --delete} UID", "Delete UID's store and index");
printf("%-25s %s\n", "{-V --verbose}", "Log events more verbosely"); printf("%-25s %s\n", "{-V --verbose}", "Log events more verbosely");
printf("\n"); printf("\n");

130
src/pkg.c
View File

@@ -13,76 +13,24 @@
#include <unistd.h> #include <unistd.h>
#include "common.h" #include "common.h"
#include "pkg.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;
/* directory definitions */ /* 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 }; const dir_t gl_usr = { "/glacier/usr", 0700 };
static const dir_t gl_usr_index = { "/glacier/usr/index", 0700 }; 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_store = { "/glacier/usr/store", 0700 };
static const dir_t gl_sys = { "/glacier/sys", 0700 }; const dir_t gl_sys = { "/glacier/sys", 0700 };
static const dir_t gl_sys_index = { "/glacier/sys/index", 0700 }; 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_store = { "/glacier/sys/store", 0700 };
/* null dependencies/conflicts for error throwing */ /* null dependencies/conflicts for error throwing */
static dep_t null_dep = { "null", {-1, -1, -1, NULL} }; dep_t null_dep = { "null", {-1, -1, -1, NULL} };
static conf_t null_conf = { "null", {-1, -1, -1, NULL} }; conf_t null_conf = { "null", {-1, -1, -1, NULL} };
static char char
*join_with_cwd(const char *path) *join_with_cwd(const char *path)
{ {
char cwd[PATH_MAX]; char cwd[PATH_MAX];
@@ -150,6 +98,7 @@ gl_pkg_t empty = {
"Null package for internal use. Returned upon an error.", "Null package for internal use. Returned upon an error.",
"null@null.null", "null@null.null",
"null", "null",
"null",
&null_dep, &null_dep,
&null_conf &null_conf
}; };
@@ -167,7 +116,7 @@ gl_mkdir(dir_t *dir)
} }
gl_pkg_t 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)); gl_pkg_t *new_pkg = malloc(sizeof(gl_pkg_t));
if (!new_pkg) { return NULL; } if (!new_pkg) { return NULL; }
@@ -177,6 +126,7 @@ gl_pkg_t
new_pkg -> pkg_desc = desc; new_pkg -> pkg_desc = desc;
new_pkg -> pkg_maint = maint; new_pkg -> pkg_maint = maint;
new_pkg -> pkg_copyright = copy; new_pkg -> pkg_copyright = copy;
new_pkg -> pkg_repo = repo;
new_pkg -> pkg_dependencies = dep; new_pkg -> pkg_dependencies = dep;
new_pkg -> pkg_conflicts = conf; 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_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_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_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); } if (config_lookup_string(&cfg, "PKG_VER", &tmp_str)) { pkg->pkg_ver = gl_parse_semver(tmp_str); }
deps = config_lookup(&cfg, "PKG_DEPS"); deps = config_lookup(&cfg, "PKG_DEPS");
if (deps && config_setting_is_list(deps)) { if (deps && config_setting_is_list(deps)) {
int count = config_setting_length(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++) { 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_name = NULL;
const char *dep_ver = 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"); confs = config_lookup(&cfg, "PKG_CONFS");
if (confs && config_setting_is_list(confs)) { if (confs && config_setting_is_list(confs)) {
int count = config_setting_length(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++) { 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_name = NULL;
const char *conf_ver = NULL; const char *conf_ver = NULL;
@@ -295,7 +246,7 @@ void
gl_free_dir(dir_t *dir) gl_free_dir(dir_t *dir)
{ {
if (dir && dir->path) { if (dir && dir->path) {
free(dir->path); free((char *)dir->path);
dir->path = NULL; dir->path = NULL;
} }
} }
@@ -309,6 +260,7 @@ gl_free_pkg(gl_pkg_t *pkg)
free(pkg->pkg_desc); free(pkg->pkg_desc);
free(pkg->pkg_maint); free(pkg->pkg_maint);
free(pkg->pkg_copyright); free(pkg->pkg_copyright);
free(pkg->pkg_repo);
gl_free_semver(&pkg->pkg_ver); 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);
}

View File

@@ -37,6 +37,7 @@ typedef struct {
char *pkg_desc; char *pkg_desc;
char *pkg_maint; char *pkg_maint;
char *pkg_copyright; char *pkg_copyright;
char *pkg_repo;
dep_t *pkg_dependencies; dep_t *pkg_dependencies;
conf_t *pkg_conflicts; conf_t *pkg_conflicts;
} }
@@ -62,8 +63,8 @@ void gl_free_semver(semver_t *v);
gl_pkg_t *gl_spawn_pkg( gl_pkg_t *gl_spawn_pkg(
char *name, semver_t *ver, char *desc, char *name, semver_t *ver, char *desc,
char *maint, char *copy, dep_t *dep, char *maint, char *copy, char *repo,
conf_t conf dep_t *dep, conf_t *conf
); );
void gl_show_pkg_props(const gl_pkg_t *pkg); 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_path(char *path);
void gl_free_dir(dir_t *dir); 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); int gl_prepare_pkgdir(gl_pkg_t *pkg, bool is_syspkg);
char *join_with_cwd(const char *path); char *join_with_cwd(const char *path);

17
src/test_backup.c Normal file
View 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;
}