Commit d6c74352 authored by Timo Teräs's avatar Timo Teräs

Initial commit of some stuff written so far. Still in state of flux. Expect

breakage and major changes.
parent 45d2c702
Natanael Copa <n@tanael.org>
Timo Teräs <timo.teras@iki.fi>
# Makefile - one file to rule them all, one file to bind them
#
# Copyright (C) 2007 Timo Teräs <timo.teras@iki.fi>
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3 as published
# by the Free Software Foundation. See http://www.gnu.org/ for details.
VERSION := 2.0-pre0
SVN_REV := $(shell svn info 2> /dev/null | grep ^Revision | cut -d ' ' -f 2)
ifneq ($(SVN_REV),)
FULL_VERSION := $(VERSION)-r$(SVN_REV)
else
FULL_VERSION := $(VERSION)
endif
CC=gcc
INSTALL=install
INSTALLDIR=$(INSTALL) -d
CFLAGS=-O2 -g -D_GNU_SOURCE -Werror -Wall -Wstrict-prototypes -std=gnu99 \
-DAPK_VERSION=\"$(FULL_VERSION)\"
LDFLAGS=-g -lpthread
DESTDIR=
SBINDIR=/usr/sbin
CONFDIR=/etc/apk
MANDIR=/usr/share/man
DOCDIR=/usr/share/doc/apk
SUBDIRS=src
.PHONY: compile install clean all
all: compile
compile install clean::
@for i in $(SUBDIRS); do $(MAKE) $(MFLAGS) -C $$i $(MAKECMDGOALS); done
install::
$(INSTALLDIR) $(DESTDIR)$(DOCDIR)
$(INSTALL) README $(DESTDIR)$(DOCDIR)
dist:
svn-clean
(TOP=`pwd` && cd .. && ln -s $$TOP apk-tools-$(VERSION) && \
tar --exclude '*/.svn*' -cjvf apk-tools-$(VERSION).tar.bz2 apk-tools-$(VERSION)/* && \
rm apk-tools-$(VERSION))
.EXPORT_ALL_VARIABLES:
- Command line parsing
- Get repositories/root from command line
- Repository index/package fetching from URLs
- Installation of local files
- Implement lbu stuff
- Error handling and rollback
- Dependency manipulation API: deletion, overwrite, check compatibility
- File ownership chowning
- New user/group creation
- Non-trivial solution finder
- Versioned dependencies
- Conflicts
- Provides
- Order removal of packages to honour dependencies
- Create reverse dependencies for installed pkgs
- Remember counts for hash table creation
- Possibly create a token hash for package names, versions and licenses, etc.
- Calculate changeset installed-size change
- Compress databases
- Option to not read fs entry cache
- Essentials(?)
- Oldies:
add, delete: read (pkgs+fs), modify DEPs, recalc+commit+write (pkgs+fs)
fetch: read (pkgs), download remote packages
fetch -u: read (pkgs), download indexes, write (pkgs)
glob: read (pkgs), operate on package db
info: read (pkgs+fs), mostly on package db, might need .apks
version: read (pkgs), compare all installed pkg versions
- New:
deps: show master dependencies
index: new TARGET, scan packages, write INDEX (pkgs)
upgrade: read TARGET, mark upgrade flags, recalculate, commit (pkgs+fs)
# Makefile - one file to rule them all, one file to bind them
#
# Copyright (C) 2007 Timo Teräs <timo.teras@iki.fi>
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3 as published
# by the Free Software Foundation. See http://www.gnu.org/ for details.
TARGETS = apk
apk_OBJS = \
state.o \
database.o \
package.o \
archive.o \
version.o \
blob.o \
hash.o \
md5.o \
add.o \
del.o \
ver.o \
index.o \
apk.o
ALL_OBJS = $(apk_OBJS)
all: $(TARGETS)
apk: $(apk_OBJS)
clean::
@rm -f $(TARGETS) $(ALL_OBJS)
install::
$(INSTALLDIR) $(DESTDIR)$(SBINDIR)
$(INSTALL) $(TARGETS) $(DESTDIR)$(SBINDIR)
/* add.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#include <stdio.h>
#include "apk_applet.h"
#include "apk_database.h"
static int add_main(int argc, char **argv)
{
struct apk_database db;
int i;
apk_db_init(&db, "/home/fabled/tmproot/");
apk_db_read_config(&db);
for (i = 0; i < argc; i++) {
struct apk_dependency dep = {
.name = apk_db_get_name(&db, argv[i]),
};
apk_deps_add(&db.world, &dep);
}
apk_db_recalculate_and_commit(&db);
apk_db_free(&db);
return 0;
}
static struct apk_applet apk_add = {
.name = "add",
.usage = "apkname...",
.main = add_main,
};
APK_DEFINE_APPLET(apk_add);
/* apk.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "apk_defines.h"
#include "apk_applet.h"
void apk_log(const char *prefix, const char *format, ...)
{
va_list va;
if (prefix != NULL)
fprintf(stderr, prefix);
va_start(va, format);
vfprintf(stderr, format, va);
va_end(va);
fprintf(stderr, "\n");
}
int usage(void)
{
struct apk_applet **a, *applet;
printf("apk-tools " APK_VERSION "\n"
"\n"
"Usage:\n");
for (a = &__start_apkapplets; a < &__stop_apkapplets; a++) {
applet = *a;
printf(" apk %s %s\n",
applet->name, applet->usage);
}
printf("\n");
return 1;
}
int main(int argc, char **argv)
{
struct apk_applet **a, *applet;
char *prog;
prog = strrchr(argv[0], '/');
if (prog == NULL)
prog = argv[0];
else
prog++;
if (strcmp(prog, "apk") == 0) {
if (argc < 2)
return usage();
prog = argv[1];
argv++;
argc--;
} else if (strncmp(prog, "apk_", 4) == 0) {
prog += 4;
} else
return usage();
for (a = &__start_apkapplets; a < &__stop_apkapplets; a++) {
applet = *a;
if (strcmp(prog, applet->name) == 0) {
argv++;
argc--;
return applet->main(argc, argv);
}
}
return usage();
}
/* apk_applet.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_APPLET_H
#define APK_APPLET_H
struct apk_applet {
const char *name;
const char *usage;
int (*main)(int argc, char **argv);
};
extern struct apk_applet *__start_apkapplets, *__stop_apkapplets;
#define APK_DEFINE_APPLET(x) \
static struct apk_applet *__applet_##x \
__attribute__((__section__("apkapplets") used)) = &x;
#endif
/* apk_archive.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_ARCHIVE
#define APK_ARCHIVE
#include <sys/types.h>
#include <pthread.h>
#include "apk_blob.h"
struct apk_archive_entry {
char *name;
char *link_target;
char *uname;
char *gname;
off_t size;
uid_t uid;
gid_t gid;
mode_t mode;
time_t mtime;
dev_t device;
int read_fd;
};
typedef int (*apk_archive_entry_parser)(struct apk_archive_entry *entry, void *ctx);
pid_t apk_open_gz(int *fd);
int apk_parse_tar(int fd, apk_archive_entry_parser parser, void *ctx);
int apk_parse_tar_gz(int fd, apk_archive_entry_parser parser, void *ctx);
apk_blob_t apk_archive_entry_read(struct apk_archive_entry *ae);
int apk_archive_entry_extract(struct apk_archive_entry *ae, const char *to);
pthread_t apk_checksum_and_tee(int *fd, void *ptr);
#endif
/* apk_blob.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_BLOB_H
#define APK_BLOB_H
#include <string.h>
struct apk_blob {
unsigned int len;
char *ptr;
};
typedef struct apk_blob apk_blob_t;
#define APK_BLOB_NULL ((apk_blob_t){0, NULL})
#define APK_BLOB_STR(str) ((apk_blob_t){strlen(str), (str)})
#define APK_BLOB_BUF(buf) ((apk_blob_t){sizeof(buf), (char *)(buf)})
#define APK_BLOB_PTR_LEN(beg,len) ((apk_blob_t){(len), (beg)})
#define APK_BLOB_PTR_PTR(beg,end) APK_BLOB_PTR_LEN((beg),(end)-(beg)+1)
char *apk_blob_cstr(apk_blob_t str);
int apk_blob_splitstr(apk_blob_t blob, char *split, apk_blob_t *l, apk_blob_t *r);
int apk_blob_rsplit(apk_blob_t blob, char split, apk_blob_t *l, apk_blob_t *r);
unsigned apk_blob_uint(apk_blob_t blob, int base);
int apk_hexdump_parse(apk_blob_t to, apk_blob_t from);
int apk_hexdump_format(int tolen, char *to, apk_blob_t from);
#endif
/* apk_database.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_PKGDB_H
#define APK_PKGDB_H
#include "apk_version.h"
#include "apk_hash.h"
#include "apk_archive.h"
#include "apk_package.h"
#define APK_MAX_REPOS 32
struct apk_db_file {
struct hlist_node dir_files_list;
struct hlist_node pkg_files_list;
struct apk_db_dir *dir;
struct apk_package *owner;
char filename[];
};
struct apk_db_dir {
apk_hash_node hash_node;
struct hlist_head files;
struct apk_db_dir *parent;
unsigned refs;
mode_t mode;
char dirname[];
};
struct apk_name {
apk_hash_node hash_node;
char *name;
struct apk_package_array *pkgs;
};
struct apk_repository {
char *url;
};
struct apk_database {
char *root;
unsigned pkg_id, num_repos;
struct apk_dependency_array *world;
struct apk_repository repos[APK_MAX_REPOS];
struct {
struct apk_hash names;
struct apk_hash packages;
} available;
struct {
struct hlist_head packages;
struct apk_hash dirs;
struct {
unsigned files;
unsigned dirs;
unsigned packages;
} stats;
} installed;
};
struct apk_name *apk_db_get_name(struct apk_database *db, const char *name);
void apk_name_free(struct apk_name *pkgname);
void apk_db_init(struct apk_database *db, const char *root);
void apk_db_free(struct apk_database *db);
int apk_db_read_config(struct apk_database *db);
int apk_db_write_config(struct apk_database *db);
int apk_db_pkg_add_file(struct apk_database *db, const char *file);
struct apk_package *apk_db_get_pkg(struct apk_database *db, csum_t sum);
int apk_db_index_read(struct apk_database *db, int fd, int repo);
void apk_db_index_write(struct apk_database *db, int fd);
int apk_db_add_repository(struct apk_database *db, const char *repo);
int apk_db_recalculate_and_commit(struct apk_database *db);
int apk_db_install_pkg(struct apk_database *db,
struct apk_package *oldpkg,
struct apk_package *newpkg);
#endif
/* apk_defines.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_DEFINES_H
#define APK_DEFINES_H
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define BIT(x) (1 << (x))
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0L
#endif
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
#if 1
#include "md5.h"
typedef md5sum_t csum_t;
typedef struct md5_ctx csum_ctx_t;
#define csum_init(ctx) md5_init(ctx)
#define csum_process(ctx, buf, len) md5_process(ctx, buf, len)
#define csum_finish(ctx, buf) md5_finish(ctx, buf)
#endif
#define apk_error(args...) apk_log("ERROR: ", args)
#define apk_warning(args...) apk_log("WARNING: ", args)
#define apk_message(args...) apk_log(NULL, args)
void apk_log(const char *prefix, const char *format, ...);
#define APK_ARRAY(array_type_name, elem_type_name) \
struct array_type_name { \
int num; \
elem_type_name item[]; \
}; \
static inline struct array_type_name * \
array_type_name##_resize(struct array_type_name *a, int size) \
{ \
struct array_type_name *tmp; \
tmp = (struct array_type_name *) \
realloc(a, sizeof(struct array_type_name) + \
size * sizeof(elem_type_name)); \
tmp->num = size; \
return tmp; \
} \
static inline elem_type_name * \
array_type_name##_add(struct array_type_name **a) \
{ \
int size = 1; \
if (*a != NULL) size += (*a)->num; \
*a = array_type_name##_resize(*a, size); \
return &(*a)->item[size-1]; \
}
#define LIST_END (void *) 0xe01
#define LIST_POISON1 (void *) 0xdeadbeef
#define LIST_POISON2 (void *) 0xabbaabba
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next;
};
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static inline int hlist_hashed(const struct hlist_node *n)
{
return n->next != NULL;
}
static inline void __hlist_del(struct hlist_node *n, struct hlist_node **pprev)
{
*pprev = n->next;
}
static inline void hlist_del(struct hlist_node *n, struct hlist_node **pprev)
{
__hlist_del(n, pprev);
n->next = LIST_POISON1;
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first ? first : LIST_END;
h->first = n;
}
static inline void hlist_add_after(struct hlist_node *n, struct hlist_node **prev)
{
n->next = *prev ? *prev : LIST_END;
*prev = n;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && pos != LIST_END; \
pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && pos != LIST_END && \
({ n = pos->next; 1; }); \
pos = n)
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && pos != LIST_END && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && pos != LIST_END && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
#endif
/* apk_hash.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_HASH_H
#define APK_HASH_H
#include <malloc.h>
#include "apk_defines.h"
typedef void *apk_hash_item;
typedef const void *apk_hash_key;
typedef unsigned long (*apk_hash_f)(apk_hash_key);
typedef int (*apk_hash_compare_f)(apk_hash_key, apk_hash_key);
typedef void (*apk_hash_delete_f)(apk_hash_item);
typedef int (*apk_hash_enumerator_f)(apk_hash_item, void *ctx);
struct apk_hash_ops {
ptrdiff_t node_offset;
apk_hash_key (*get_key)(apk_hash_item item);
unsigned long (*hash_key)(apk_hash_key key);
int (*compare)(apk_hash_key key, apk_hash_key item);
void (*delete_item)(apk_hash_item item);
};
typedef struct hlist_node apk_hash_node;
APK_ARRAY(apk_hash_array, struct hlist_head);
struct apk_hash {
const struct apk_hash_ops *ops;
struct apk_hash_array *buckets;
int num_items;
};
unsigned long apk_hash_string(const char *string);
unsigned long apk_hash_csum(const void *);
void apk_hash_init(struct apk_hash *h, const struct apk_hash_ops *ops,
int num_buckets);
void apk_hash_free(struct apk_hash *h);
int apk_hash_foreach(struct apk_hash *h, apk_hash_enumerator_f e, void *ctx);
apk_hash_item apk_hash_get(struct apk_hash *h, apk_hash_key key);
void apk_hash_insert(struct apk_hash *h, apk_hash_item item);
void apk_hash_delete(struct apk_hash *h, apk_hash_key key);
#endif
/* apk_database.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#ifndef APK_PKG_H
#define APK_PKG_H
#include "apk_version.h"
#include "apk_hash.h"
struct apk_database;
struct apk_name;
#define APK_SCRIPT_PRE_INSTALL 0
#define APK_SCRIPT_POST_INSTALL 1
#define APK_SCRIPT_PRE_DEINSTALL 2
#define APK_SCRIPT_POST_DEINSTALL 3
#define APK_SCRIPT_PRE_UPGRADE 4
#define APK_SCRIPT_POST_UPGRADE 5
struct apk_script {
struct hlist_node script_list;
unsigned int type;
unsigned int size;
char script[];
};
struct apk_dependency {
unsigned conflict : 1;
unsigned prefer_upgrade : 1;
unsigned version_mask : 3;
struct apk_name *name;
char *version;
};
APK_ARRAY(apk_dependency_array, struct apk_dependency);
struct apk_package {
apk_hash_node hash_node;
csum_t csum;
unsigned id, repos;
struct apk_name *name;
char *version;
char *url, *description, *license;
struct apk_dependency_array *depends;
unsigned int installed_size, size;
/* for installed packages only */
struct hlist_node installed_pkgs_list;
struct hlist_head owned_files;
struct hlist_head scripts;
};
APK_ARRAY(apk_package_array, struct apk_package *);
int apk_deps_add(struct apk_dependency_array **depends,
struct apk_dependency *dep);
void apk_deps_parse(struct apk_database *db,
struct apk_dependency_array **depends,
apk_blob_t blob);
int apk_deps_format(char *buf, int size,
struct apk_dependency_array *depends);
int apk_script_type(const char *name);
struct apk_package *apk_pkg_read(struct apk_database *db, const char *name);
void apk_pkg_free(struct apk_package *pkg);
int apk_pkg_get_state(struct apk_package *pkg);
int apk_pkg_add_script(struct apk_package *pkg, int fd,
unsigned int type, unsigned int size);
int apk_pkg_run_script(struct apk_package *pkg, const char *root,
unsigned int type);
struct apk_package *apk_pkg_parse_index_entry(struct apk_database *db, apk_blob_t entry);
apk_blob_t apk_pkg_format_index_entry(struct apk_package *pkg, int size, char *buf);
#endif
/* apk_state.h - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*