Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -1,3 +1,2 @@ -appfsd -appfsd.o -appfsd.tcl.h +workdir-* +ARCHIVE DELETED Makefile Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,43 +0,0 @@ -CC = gcc -PKG_CONFIG = pkg-config -CFLAGS = -Wall $(shell $(PKG_CONFIG) --cflags fuse) $(shell $(PKG_CONFIG) --cflags sqlite3) $(TCL_CFLAGS) -LDFLAGS = $(TCL_LDFLAGS) -LIBS = $(shell $(PKG_CONFIG) --libs fuse) $(shell $(PKG_CONFIG) --libs sqlite3) $(TCL_LIBS) -PREFIX = /usr/local -prefix = $(PREFIX) -bindir = $(prefix)/bin -sbindir = $(prefix)/sbin - -ifneq ($(TCLKIT_SDK_DIR),) -TCLCONFIG_SH_PATH = $(TCLKIT_SDK_DIR)/lib/tclConfig.sh -TCL_LDFLAGS = -Wl,-R,$(TCLKIT_SDK_DIR)/lib -export TCLKIT_SDK_DIR -else -TCLCONFIG_SH_PATH = $(shell echo 'puts [::tcl::pkgconfig get libdir,install]' | tclsh)/tclConfig.sh -endif -TCL_CFLAGS = $(shell . $(TCLCONFIG_SH_PATH); echo "$${TCL_INCLUDE_SPEC}") -TCL_LIBS = $(shell . $(TCLCONFIG_SH_PATH); echo "$${TCL_LIB_SPEC}") - -all: appfsd - -appfsd: appfsd.o - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o appfsd appfsd.o $(LIBS) - -appfsd.o: appfsd.c appfsd.tcl.h - $(CC) $(CPPFLAGS) $(CFLAGS) -o appfsd.o -c appfsd.c - -appfsd.tcl.h: appfsd.tcl - sed 's@[\\"]@\\&@g;s@^@ "@;s@$$@\\n"@' appfsd.tcl > appfsd.tcl.h.new - mv appfsd.tcl.h.new appfsd.tcl.h - -install: appfsd - if [ ! -d '$(DESTDIR)$(sbindir)' ]; then mkdir -p '$(DESTDIR)$(sbindir)'; chmod 755 '$(DESTDIR)$(sbindir)'; fi - cp appfsd '$(DESTDIR)$(sbindir)/' - -clean: - rm -f appfsd appfsd.o - rm -f appfsd.tcl.h - -distclean: clean - -.PHONY: all test clean distclean install DELETED README.md Index: README.md ================================================================== --- README.md +++ README.md @@ -1,41 +0,0 @@ -AppFS -===== -It's sort of like LazyFS. - -Usage ------ -Run: - 1. # mkdir /tmp/appfs-cache /opt/appfs - 2. # appfsd /opt/appfs - - -Paths ------ - AppFS should normally be mounted on "/opt/appfs". - - /opt/appfs/hostname - Fetches: http://hostname/appfs/index - Contains CSV file: hash,extraData - Fetches: http://hostname/appfs/sha1/ - Contains CSV file: package,version,os,cpuArch,sha1,isLatest - - /opt/appfs/hostname/package/os-cpuArch/version - /opt/appfs/hostname/sha1/ - Fetches: http://hostname/appfs/sha1/ - Contains CSV file: - type,time,extraData,name - type == directory; extraData = (null) - type == symlink; extraData = source - type == file; extraData = size,perms,sha1 - - /opt/appfs/hostname/{sha1,package/os-cpuArch/version}/file - Fetches: http://hostname/appfs/sha1/ - -Database --------- - packages(hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest) - files(package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory) - -Resources ---------- -http://appfs.rkeene.org/ DELETED appfs-mkfs Index: appfs-mkfs ================================================================== --- appfs-mkfs +++ appfs-mkfs @@ -1,134 +0,0 @@ -#! /usr/bin/env bash - -pkgsdir="$1" -appfsdir="$2" - -if [ -z "${pkgsdir}" -o -z "${appfsdir}" ]; then - echo 'Usage: appfs-mk ' >&2 - - exit 1 -fi - -appfsdir="$(cd "${appfsdir}" && pwd)" -if [ -z "${appfsdir}" ]; then - echo "Unable to find appfs directory." >&2 - - exit 1 -fi - -mkdir -p "${appfsdir}/sha1" - -function sha1() { - local filename - - filename="$1" - - openssl sha1 "${filename}" | sed 's@.*= @@' -} - -function emit_manifest() { - find . -print0 | while IFS='' read -r -d $'\0' filename; do - if [ "${filename}" = '.' ]; then - continue - fi - - filename="$(echo "${filename}" | sed 's@^\./@@' | head -n 1)" - - if [ ! -e "${filename}" ]; then - continue - fi - - if [ -h "${filename}" ]; then - type='symlink' - elif [ -d "${filename}" ]; then - type='directory' - elif [ -f "${filename}" ]; then - type='file' - else - continue - fi - - case "${type}" in - directory) - stat_format='%Y' - extra_data='' - ;; - symlink) - stat_format='%Y' - extra_data="$(readlink "${filename}")" - ;; - file) - if [ -x "${filename}" ]; then - extra_data='x' - else - extra_data='' - fi - - stat_format='%Y,%s' - filename_hash="$(sha1 "${filename}")" - extra_data="${extra_data},${filename_hash}" - - filename_intree="${appfsdir}/sha1/${filename_hash}" - - if [ ! -e "${filename_intree}" ]; then - cat "${filename}" > "${filename_intree}.tmp" - - mv "${filename_intree}.tmp" "${filename_intree}" - fi - ;; - esac - stat_data="$(stat --format="${stat_format}" "${filename}")" - - if [ -z "${extra_data}" ]; then - echo "${type},${stat_data},${filename}" - else - echo "${type},${stat_data},${extra_data},${filename}" - fi - done -} - -cd "${pkgsdir}" || exit 1 - -packagelistfile="${appfsdir}/sha1/${RANDOM}${RANDOM}${RANDOM}${RANDOM}${RANDOM}.tmp" -for package in *; do - ( - cd "${package}" || exit 1 - - for os_cpuArch in *; do - os="$(echo "${os_cpuArch}" | cut -f 1 -d '-')" - cpuArch="$(echo "${os_cpuArch}" | cut -f 2- -d '-')" - - ( - cd "${os_cpuArch}" || exit 1 - - for version in *; do - if [ -h "${version}" ]; then - continue - fi - - manifestfile="${appfsdir}/sha1/${RANDOM}${RANDOM}${RANDOM}${RANDOM}${RANDOM}.tmp" - - ( - cd "${version}" || exit 1 - - emit_manifest - ) > "${manifestfile}" - - manifestfile_hash="$(sha1 "${manifestfile}")" - mv "${manifestfile}" "${appfsdir}/sha1/${manifestfile_hash}" - - # XXX:TODO: Determine if this is the latest version - isLatest='0' - - echo "${package},${version},${os},${cpuArch},${manifestfile_hash},${isLatest}" - done - - ) - done - ) - -done > "${packagelistfile}" -packagelistfile_hash="$(sha1 "${packagelistfile}")" -mv "${packagelistfile}" "${appfsdir}/sha1/${packagelistfile_hash}" - -echo "${packagelistfile_hash},sha1" > "${appfsdir}/index" DELETED appfsd.c Index: appfsd.c ================================================================== --- appfsd.c +++ appfsd.c @@ -1,910 +0,0 @@ -#define FUSE_USE_VERSION 26 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define APPFS_CACHEDIR "/var/cache/appfs" - -#define APPFS_DEBUG(x...) { fprintf(stderr, "[debug] %s:%i:%s: ", __FILE__, __LINE__, __func__); fprintf(stderr, x); fprintf(stderr, "\n"); } - -static pthread_key_t interpKey; - -struct appfs_thread_data { - sqlite3 *db; - const char *cachedir; - time_t boottime; -}; - -struct appfs_thread_data globalThread; - -typedef enum { - APPFS_PATHTYPE_INVALID, - APPFS_PATHTYPE_FILE, - APPFS_PATHTYPE_DIRECTORY, - APPFS_PATHTYPE_SYMLINK -} appfs_pathtype_t; - -struct appfs_children { - struct appfs_children *_next; - int counter; - - char name[256]; -}; - -struct appfs_pathinfo { - appfs_pathtype_t type; - time_t time; - char hostname[256]; - union { - struct { - int childcount; - } dir; - struct { - int executable; - off_t size; - char sha1[41]; - } file; - struct { - off_t size; - char source[256]; - } symlink; - } typeinfo; -}; - -struct appfs_sqlite3_query_cb_handle { - struct appfs_children *head; - int argc; - const char *fmt; -}; - -static Tcl_Interp *appfs_create_TclInterp(const char *cachedir) { - Tcl_Interp *interp; - int tcl_ret; - - interp = Tcl_CreateInterp(); - if (interp == NULL) { - fprintf(stderr, "Unable to create Tcl Interpreter. Aborting.\n"); - - return(NULL); - } - - tcl_ret = Tcl_Init(interp); - if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl. Aborting.\n"); - - return(NULL); - } - - tcl_ret = Tcl_Eval(interp, "" -#include "appfsd.tcl.h" - ""); - if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl AppFS script. Aborting.\n"); - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); - - return(NULL); - } - - if (Tcl_SetVar(interp, "::appfs::cachedir", cachedir, TCL_GLOBAL_ONLY) == NULL) { - fprintf(stderr, "Unable to set cache directory. This should never fail.\n"); - - return(NULL); - } - - tcl_ret = Tcl_Eval(interp, "::appfs::init"); - if (tcl_ret != TCL_OK) { - fprintf(stderr, "Unable to initialize Tcl AppFS script (::appfs::init). Aborting.\n"); - fprintf(stderr, "Tcl Error is: %s\n", Tcl_GetStringResult(interp)); - - return(NULL); - } - - return(interp); -} - -static int appfs_Tcl_Eval(Tcl_Interp *interp, int objc, const char *cmd, ...) { - Tcl_Obj **objv; - const char *arg; - va_list argp; - int retval; - int i; - - objv = (void *) ckalloc(sizeof(*objv) * objc); - objv[0] = Tcl_NewStringObj(cmd, -1); - Tcl_IncrRefCount(objv[0]); - - va_start(argp, cmd); - for (i = 1; i < objc; i++) { - arg = va_arg(argp, const char *); - objv[i] = Tcl_NewStringObj(arg, -1); - Tcl_IncrRefCount(objv[i]); - } - va_end(argp); - - retval = Tcl_EvalObjv(interp, objc, objv, 0); - - for (i = 0; i < objc; i++) { - Tcl_DecrRefCount(objv[i]); - } - - ckfree((void *) objv); - - if (retval != TCL_OK) { - APPFS_DEBUG("Tcl command failed, ::errorInfo contains: %s\n", Tcl_GetVar(interp, "::errorInfo", 0)); - } - - return(retval); -} - -static void appfs_update_index(const char *hostname) { - Tcl_Interp *interp; - int tcl_ret; - - APPFS_DEBUG("Enter: hostname = %s", hostname); - - interp = pthread_getspecific(interpKey); - if (interp == NULL) { - interp = appfs_create_TclInterp(globalThread.cachedir); - - pthread_setspecific(interpKey, interp); - } - - tcl_ret = appfs_Tcl_Eval(interp, 2, "::appfs::getindex", hostname); - if (tcl_ret != TCL_OK) { - APPFS_DEBUG("Call to ::appfs::getindex failed: %s", Tcl_GetStringResult(interp)); - - return; - } - - return; -} - -static const char *appfs_getfile(const char *hostname, const char *sha1) { - Tcl_Interp *interp; - char *retval; - int tcl_ret; - - interp = pthread_getspecific(interpKey); - if (interp == NULL) { - interp = appfs_create_TclInterp(globalThread.cachedir); - - pthread_setspecific(interpKey, interp); - } - - tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::download", hostname, sha1); - if (tcl_ret != TCL_OK) { - APPFS_DEBUG("Call to ::appfs::download failed: %s", Tcl_GetStringResult(interp)); - - return(NULL); - } - - retval = strdup(Tcl_GetStringResult(interp)); - - return(retval); -} - -static void appfs_update_manifest(const char *hostname, const char *sha1) { - Tcl_Interp *interp; - int tcl_ret; - - interp = pthread_getspecific(interpKey); - if (interp == NULL) { - interp = appfs_create_TclInterp(globalThread.cachedir); - - pthread_setspecific(interpKey, interp); - } - - tcl_ret = appfs_Tcl_Eval(interp, 3, "::appfs::getpkgmanifest", hostname, sha1); - if (tcl_ret != TCL_OK) { - APPFS_DEBUG("Call to ::appfs::getpkgmanifest failed: %s", Tcl_GetStringResult(interp)); - - return; - } - - return; -} - -#define appfs_free_list_type(id, type) static void appfs_free_list_ ## id(type *head) { \ - type *obj, *next; \ - for (obj = head; obj; obj = next) { \ - next = obj->_next; \ - ckfree((void *) obj); \ - } \ -} - -appfs_free_list_type(children, struct appfs_children) - -static int appfs_getchildren_cb(void *_head, int columns, char **values, char **names) { - struct appfs_children **head_p, *obj; - - head_p = _head; - - obj = (void *) ckalloc(sizeof(*obj)); - - snprintf(obj->name, sizeof(obj->name), "%s", values[0]); - - if (*head_p == NULL) { - obj->counter = 0; - } else { - obj->counter = (*head_p)->counter + 1; - } - - obj->_next = *head_p; - *head_p = obj; - - return(0); - -} - -static struct appfs_children *appfs_getchildren(const char *hostname, const char *package_hash, const char *path, int *children_count_p) { - struct appfs_children *head = NULL; - char *sql; - int sqlite_ret; - - if (children_count_p == NULL) { - return(NULL); - } - - appfs_update_index(hostname); - appfs_update_manifest(hostname, package_hash); - - sql = sqlite3_mprintf("SELECT file_name FROM files WHERE package_sha1 = %Q AND file_directory = %Q;", package_hash, path); - if (sql == NULL) { - APPFS_DEBUG("Call to sqlite3_mprintf failed."); - - return(NULL); - } - - APPFS_DEBUG("SQL: %s", sql); - sqlite_ret = sqlite3_exec(globalThread.db, sql, appfs_getchildren_cb, &head, NULL); - sqlite3_free(sql); - - if (sqlite_ret != SQLITE_OK) { - APPFS_DEBUG("Call to sqlite3_exec failed."); - - return(NULL); - } - - if (head != NULL) { - *children_count_p = head->counter + 1; - } - - return(head); -} - -static int appfs_sqlite3_query_cb(void *_cb_handle, int columns, char **values, char **names) { - struct appfs_sqlite3_query_cb_handle *cb_handle; - struct appfs_children *obj; - - cb_handle = _cb_handle; - - obj = (void *) ckalloc(sizeof(*obj)); - - switch (cb_handle->argc) { - case 1: - snprintf(obj->name, sizeof(obj->name), cb_handle->fmt, values[0]); - break; - case 2: - snprintf(obj->name, sizeof(obj->name), cb_handle->fmt, values[0], values[1]); - break; - case 3: - snprintf(obj->name, sizeof(obj->name), cb_handle->fmt, values[0], values[1], values[2]); - break; - case 4: - snprintf(obj->name, sizeof(obj->name), cb_handle->fmt, values[0], values[1], values[2], values[3]); - break; - } - - if (cb_handle->head == NULL) { - obj->counter = 0; - } else { - obj->counter = cb_handle->head->counter + 1; - } - - obj->_next = cb_handle->head; - cb_handle->head = obj; - - return(0); -} - -static struct appfs_children *appfs_sqlite3_query(char *sql, int argc, const char *fmt, int *results_count_p) { - struct appfs_sqlite3_query_cb_handle cb_handle; - int sqlite_ret; - - if (results_count_p == NULL) { - return(NULL); - } - - if (sql == NULL) { - APPFS_DEBUG("Call to sqlite3_mprintf probably failed."); - - return(NULL); - } - - if (fmt == NULL) { - fmt = "%s"; - } - - cb_handle.head = NULL; - cb_handle.argc = argc; - cb_handle.fmt = fmt; - - APPFS_DEBUG("SQL: %s", sql); - sqlite_ret = sqlite3_exec(globalThread.db, sql, appfs_sqlite3_query_cb, &cb_handle, NULL); - sqlite3_free(sql); - - if (sqlite_ret != SQLITE_OK) { - APPFS_DEBUG("Call to sqlite3_exec failed."); - - return(NULL); - } - - if (cb_handle.head != NULL) { - *results_count_p = cb_handle.head->counter + 1; - } - - return(cb_handle.head); -} - -static int appfs_lookup_package_hash_cb(void *_retval, int columns, char **values, char **names) { - char **retval = _retval; - - *retval = strdup(values[0]); - - return(0); -} - -static char *appfs_lookup_package_hash(const char *hostname, const char *package, const char *os, const char *cpuArch, const char *version) { - char *sql; - char *retval = NULL; - int sqlite_ret; - - appfs_update_index(hostname); - - sql = sqlite3_mprintf("SELECT sha1 FROM packages WHERE hostname = %Q AND package = %Q AND os = %Q AND cpuArch = %Q AND version = %Q;", - hostname, - package, - os, - cpuArch, - version - ); - if (sql == NULL) { - APPFS_DEBUG("Call to sqlite3_mprintf failed."); - - return(NULL); - } - - APPFS_DEBUG("SQL: %s", sql); - sqlite_ret = sqlite3_exec(globalThread.db, sql, appfs_lookup_package_hash_cb, &retval, NULL); - sqlite3_free(sql); - - if (sqlite_ret != SQLITE_OK) { - APPFS_DEBUG("Call to sqlite3_exec failed."); - - return(NULL); - } - - return(retval); -} - -static int appfs_getfileinfo_cb(void *_pathinfo, int columns, char **values, char **names) { - struct appfs_pathinfo *pathinfo = _pathinfo; - const char *type, *time, *source, *size, *perms, *sha1; - - type = values[0]; - time = values[1]; - source = values[2]; - size = values[3]; - perms = values[4]; - sha1 = values[5]; - - pathinfo->time = strtoull(time, NULL, 10); - - if (strcmp(type, "file") == 0) { - pathinfo->type = APPFS_PATHTYPE_FILE; - - if (!size) { - size = "0"; - } - - if (!perms) { - perms = ""; - } - - if (!sha1) { - sha1 = ""; - } - - pathinfo->typeinfo.file.size = strtoull(size, NULL, 10); - snprintf(pathinfo->typeinfo.file.sha1, sizeof(pathinfo->typeinfo.file.sha1), "%s", sha1); - - if (strcmp(perms, "x") == 0) { - pathinfo->typeinfo.file.executable = 1; - } else { - pathinfo->typeinfo.file.executable = 0; - } - - return(0); - } - - if (strcmp(type, "directory") == 0) { - pathinfo->type = APPFS_PATHTYPE_DIRECTORY; - pathinfo->typeinfo.dir.childcount = 0; - - return(0); - } - - if (strcmp(type, "symlink") == 0) { - pathinfo->type = APPFS_PATHTYPE_SYMLINK; - pathinfo->typeinfo.dir.childcount = 0; - - if (!source) { - source = ".BADLINK"; - } - - pathinfo->typeinfo.symlink.size = strlen(source); - snprintf(pathinfo->typeinfo.symlink.source, sizeof(pathinfo->typeinfo.symlink.source), "%s", source); - - return(0); - } - - return(0); - - /* Until this is used, prevent the compiler from complaining */ - source = source; -} - -static int appfs_getfileinfo(const char *hostname, const char *package_hash, const char *_path, struct appfs_pathinfo *pathinfo) { - char *directory, *file, *path; - char *sql; - int sqlite_ret; - - if (pathinfo == NULL) { - return(-EIO); - } - - appfs_update_index(hostname); - appfs_update_manifest(hostname, package_hash); - - path = strdup(_path); - directory = path; - file = strrchr(path, '/'); - if (file == NULL) { - file = path; - directory = ""; - } else { - *file = '\0'; - file++; - } - - sql = sqlite3_mprintf("SELECT type, time, source, size, perms, file_sha1 FROM files WHERE package_sha1 = %Q AND file_directory = %Q AND file_name = %Q;", package_hash, directory, file); - if (sql == NULL) { - APPFS_DEBUG("Call to sqlite3_mprintf failed."); - - free(path); - - return(-EIO); - } - - free(path); - - pathinfo->type = APPFS_PATHTYPE_INVALID; - - APPFS_DEBUG("SQL: %s", sql); - sqlite_ret = sqlite3_exec(globalThread.db, sql, appfs_getfileinfo_cb, pathinfo, NULL); - sqlite3_free(sql); - - if (sqlite_ret != SQLITE_OK) { - APPFS_DEBUG("Call to sqlite3_exec failed."); - - return(-EIO); - } - - if (pathinfo->type == APPFS_PATHTYPE_INVALID) { - return(-ENOENT); - } - - return(0); -} - -static int appfs_get_path_info_sql(char *sql, int argc, const char *fmt, struct appfs_pathinfo *pathinfo, struct appfs_children **children) { - struct appfs_children *node, *dir_children, *dir_child; - int dir_children_count = 0; - - dir_children = appfs_sqlite3_query(sql, argc, fmt, &dir_children_count); - - if (dir_children == NULL || dir_children_count == 0) { - return(-ENOENT); - } - - /* Request for a single hostname */ - pathinfo->type = APPFS_PATHTYPE_DIRECTORY; - pathinfo->typeinfo.dir.childcount = dir_children_count; - pathinfo->time = globalThread.boottime; - - if (children) { - for (dir_child = dir_children; dir_child; dir_child = dir_child->_next) { - node = (void *) ckalloc(sizeof(*node)); - node->_next = *children; - strcpy(node->name, dir_child->name); - *children = node; - } - } - - appfs_free_list_children(dir_children); - - return(0); -} -/* Get information about a path, and optionally list children */ -static int appfs_get_path_info(const char *_path, struct appfs_pathinfo *pathinfo, struct appfs_children **children) { - struct appfs_children *dir_children; - char *hostname, *packagename, *os_cpuArch, *os, *cpuArch, *version; - char *path, *path_s; - char *package_hash; - char *sql; - int files_count; - int fileinfo_ret, retval; - - if (children) { - *children = NULL; - } - - if (_path == NULL) { - return(-ENOENT); - } - - if (_path[0] != '/') { - return(-ENOENT); - } - - if (_path[1] == '\0') { - /* Request for the root directory */ - pathinfo->hostname[0] = '\0'; - - sql = sqlite3_mprintf("SELECT DISTINCT hostname FROM packages;"); - - retval = appfs_get_path_info_sql(sql, 1, NULL, pathinfo, children); - - /* The root directory always exists, even if it has no subordinates */ - if (retval != 0) { - pathinfo->type = APPFS_PATHTYPE_DIRECTORY; - pathinfo->typeinfo.dir.childcount = 0; - pathinfo->time = globalThread.boottime; - - retval = 0; - } - - return(retval); - } - - path = strdup(_path); - path_s = path; - - hostname = path + 1; - packagename = strchr(hostname, '/'); - - if (packagename != NULL) { - *packagename = '\0'; - packagename++; - } - - snprintf(pathinfo->hostname, sizeof(pathinfo->hostname), "%s", hostname); - - if (packagename == NULL) { - appfs_update_index(hostname); - - sql = sqlite3_mprintf("SELECT DISTINCT package FROM packages WHERE hostname = %Q;", hostname); - - free(path_s); - - return(appfs_get_path_info_sql(sql, 1, NULL, pathinfo, children)); - } - - os_cpuArch = strchr(packagename, '/'); - - if (os_cpuArch != NULL) { - *os_cpuArch = '\0'; - os_cpuArch++; - } - - if (os_cpuArch == NULL) { - appfs_update_index(hostname); - - sql = sqlite3_mprintf("SELECT DISTINCT os, cpuArch FROM packages WHERE hostname = %Q AND package = %Q;", hostname, packagename); - - free(path_s); - - return(appfs_get_path_info_sql(sql, 2, "%s-%s", pathinfo, children)); - } - - version = strchr(os_cpuArch, '/'); - - if (version != NULL) { - *version = '\0'; - version++; - } - - os = os_cpuArch; - cpuArch = strchr(os_cpuArch, '-'); - if (cpuArch) { - *cpuArch = '\0'; - cpuArch++; - } - - if (version == NULL) { - /* Request for version list for a package on an OS/CPU */ - appfs_update_index(hostname); - - sql = sqlite3_mprintf("SELECT DISTINCT version FROM packages WHERE hostname = %Q AND package = %Q AND os = %Q and cpuArch = %Q;", hostname, packagename, os, cpuArch); - - free(path_s); - - return(appfs_get_path_info_sql(sql, 1, NULL, pathinfo, children)); - } - - path = strchr(version, '/'); - if (path == NULL) { - path = ""; - } else { - *path = '\0'; - path++; - } - - /* Request for a file in a specific package */ - APPFS_DEBUG("Requesting information for hostname = %s, package = %s, os = %s, cpuArch = %s, version = %s, path = %s", - hostname, packagename, os, cpuArch, version, path - ); - - package_hash = appfs_lookup_package_hash(hostname, packagename, os, cpuArch, version); - if (package_hash == NULL) { - free(path_s); - - return(-ENOENT); - } - - APPFS_DEBUG(" ... which hash a hash of %s", package_hash); - - appfs_update_manifest(hostname, package_hash); - - if (strcmp(path, "") == 0) { - pathinfo->type = APPFS_PATHTYPE_DIRECTORY; - pathinfo->time = globalThread.boottime; - } else { - fileinfo_ret = appfs_getfileinfo(hostname, package_hash, path, pathinfo); - if (fileinfo_ret != 0) { - free(path_s); - - return(fileinfo_ret); - } - } - - if (pathinfo->type == APPFS_PATHTYPE_DIRECTORY) { - dir_children = appfs_getchildren(hostname, package_hash, path, &files_count); - - if (dir_children != NULL) { - pathinfo->typeinfo.dir.childcount = files_count; - } - - if (children) { - *children = dir_children; - } - } - - free(path_s); - - return(0); -} - -static int appfs_fuse_readlink(const char *path, char *buf, size_t size) { - struct appfs_pathinfo pathinfo; - int res = 0; - - APPFS_DEBUG("Enter (path = %s, ...)", path); - - pathinfo.type = APPFS_PATHTYPE_INVALID; - - res = appfs_get_path_info(path, &pathinfo, NULL); - if (res != 0) { - return(res); - } - - if (pathinfo.type != APPFS_PATHTYPE_SYMLINK) { - return(-EINVAL); - } - - if ((strlen(pathinfo.typeinfo.symlink.source) + 1) > size) { - return(-ENAMETOOLONG); - } - - memcpy(buf, pathinfo.typeinfo.symlink.source, strlen(pathinfo.typeinfo.symlink.source) + 1); - - return(0); -} - -static int appfs_fuse_getattr(const char *path, struct stat *stbuf) { - struct appfs_pathinfo pathinfo; - int res = 0; - - APPFS_DEBUG("Enter (path = %s, ...)", path); - - pathinfo.type = APPFS_PATHTYPE_INVALID; - - res = appfs_get_path_info(path, &pathinfo, NULL); - if (res != 0) { - return(res); - } - - memset(stbuf, 0, sizeof(struct stat)); - - stbuf->st_mtime = pathinfo.time; - stbuf->st_ctime = pathinfo.time; - stbuf->st_atime = pathinfo.time; - - switch (pathinfo.type) { - case APPFS_PATHTYPE_DIRECTORY: - stbuf->st_mode = S_IFDIR | 0555; - stbuf->st_nlink = 2 + pathinfo.typeinfo.dir.childcount; - break; - case APPFS_PATHTYPE_FILE: - if (pathinfo.typeinfo.file.executable) { - stbuf->st_mode = S_IFREG | 0555; - } else { - stbuf->st_mode = S_IFREG | 0444; - } - - stbuf->st_nlink = 1; - stbuf->st_size = pathinfo.typeinfo.file.size; - break; - case APPFS_PATHTYPE_SYMLINK: - stbuf->st_mode = S_IFLNK | 0555; - stbuf->st_nlink = 1; - stbuf->st_size = pathinfo.typeinfo.symlink.size; - break; - case APPFS_PATHTYPE_INVALID: - res = -EIO; - - break; - } - - return res; -} - -static int appfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { - struct appfs_pathinfo pathinfo; - struct appfs_children *children, *child; - int retval; - - APPFS_DEBUG("Enter (path = %s, ...)", path); - - retval = appfs_get_path_info(path, &pathinfo, &children); - if (retval != 0) { - return(retval); - } - - filler(buf, ".", NULL, 0); - filler(buf, "..", NULL, 0); - - for (child = children; child; child = child->_next) { - filler(buf, child->name, NULL, 0); - } - - appfs_free_list_children(children); - - return(0); -} - -static int appfs_fuse_open(const char *path, struct fuse_file_info *fi) { - struct appfs_pathinfo pathinfo; - const char *real_path; - int fh; - int gpi_ret; - - APPFS_DEBUG("Enter (path = %s, ...)", path); - - if ((fi->flags & 3) != O_RDONLY) { - return(-EACCES); - } - - gpi_ret = appfs_get_path_info(path, &pathinfo, NULL); - if (gpi_ret != 0) { - return(gpi_ret); - } - - if (pathinfo.type == APPFS_PATHTYPE_DIRECTORY) { - return(-EISDIR); - } - - real_path = appfs_getfile(pathinfo.hostname, pathinfo.typeinfo.file.sha1); - if (real_path == NULL) { - return(-EIO); - } - - fh = open(real_path, O_RDONLY); - free((void *) real_path); - if (fh < 0) { - return(-EIO); - } - - fi->fh = fh; - - return(0); -} - -static int appfs_fuse_close(const char *path, struct fuse_file_info *fi) { - int close_ret; - - close_ret = close(fi->fh); - if (close_ret != 0) { - return(-EIO); - } - - return(0); -} - -static int appfs_fuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { - off_t lseek_ret; - ssize_t read_ret; - - APPFS_DEBUG("Enter (path = %s, ...)", path); - - lseek_ret = lseek(fi->fh, offset, SEEK_SET); - if (lseek_ret != offset) { - return(-EIO); - } - - read_ret = read(fi->fh, buf, size); - - return(read_ret); -} - -static struct fuse_operations appfs_oper = { - .getattr = appfs_fuse_getattr, - .readdir = appfs_fuse_readdir, - .readlink = appfs_fuse_readlink, - .open = appfs_fuse_open, - .release = appfs_fuse_close, - .read = appfs_fuse_read -}; - -int main(int argc, char **argv) { - const char *cachedir = APPFS_CACHEDIR; - char dbfilename[1024]; - int pthread_ret, snprintf_ret, sqlite_ret; - - globalThread.cachedir = cachedir; - globalThread.boottime = time(NULL); - - pthread_ret = pthread_key_create(&interpKey, NULL); - if (pthread_ret != 0) { - fprintf(stderr, "Unable to create TSD key for Tcl. Aborting.\n"); - - return(1); - } - - snprintf_ret = snprintf(dbfilename, sizeof(dbfilename), "%s/%s", cachedir, "cache.db"); - if (snprintf_ret >= sizeof(dbfilename)) { - fprintf(stderr, "Unable to set database filename. Aborting.\n"); - - return(1); - } - - sqlite_ret = sqlite3_open(dbfilename, &globalThread.db); - if (sqlite_ret != SQLITE_OK) { - fprintf(stderr, "Unable to open database: %s\n", dbfilename); - - return(1); - } - - return(fuse_main(argc, argv, &appfs_oper, NULL)); -} - DELETED appfsd.tcl Index: appfsd.tcl ================================================================== --- appfsd.tcl +++ appfsd.tcl @@ -1,314 +0,0 @@ -#! /usr/bin/env tclsh - -package require http 2.7 -package require sqlite3 - -namespace eval ::appfs { - variable cachedir "/tmp/appfs-cache" - variable ttl 3600 - variable nttl 60 - - proc _hash_sep {hash {seps 4}} { - for {set idx 0} {$idx < $seps} {incr idx} { - append retval "[string range $hash [expr {$idx * 2}] [expr {($idx * 2) + 1}]]/" - } - append retval "[string range $hash [expr {$idx * 2}] end]" - - return $retval - } - - proc _cachefile {url key {keyIsHash 1}} { - set filekey $key - if {$keyIsHash} { - set filekey [_hash_sep $filekey] - } - - set file [file join $::appfs::cachedir $filekey] - - file mkdir [file dirname $file] - - if {![file exists $file]} { - set tmpfile "${file}.new" - - set fd [open $tmpfile "w"] - fconfigure $fd -translation binary - - catch { - set token [::http::geturl $url -channel $fd -binary true] - } - - if {[info exists token]} { - set ncode [::http::ncode $token] - ::http::reset $token - } else { - set ncode "900" - } - - close $fd - - if {$keyIsHash} { - catch { - set hash [string tolower [exec openssl sha1 $tmpfile]] - regsub {.*= *} $hash {} hash - } - } else { - set hash $key - } - - if {$ncode == "200" && $hash == $key} { - file rename -force -- $tmpfile $file - } else { - file delete -force -- $tmpfile - } - } - - return $file - } - - - proc _isHash {value} { - set value [string tolower $value] - - if {[string length $value] != 40} { - return false - } - - if {![regexp {^[0-9a-f]*$} $value]} { - return false - } - - return true - } - - proc _db {args} { - return [uplevel 1 [list ::appfs::db {*}$args]] - } - - proc _normalizeOS {os} { - set os [string tolower [string trim $os]] - - switch -- $os { - "linux" - "freebsd" - "openbsd" - "netbsd" { - return $os - } - "sunos" { - return "solaris" - } - } - - return -code error "Unable to normalize OS: $os" - } - - proc _normalizeCPU {cpu} { - set cpu [string tolower [string trim $cpu]] - - switch -glob -- $cpu { - "i?86" { - return "ix86" - } - "x86_64" { - return $cpu - } - } - - return -code error "Unable to normalize CPU: $cpu" - } - - proc init {} { - if {[info exists ::appfs::init_called]} { - return - } - - set ::appfs::init_called 1 - - if {![info exists ::appfs::db]} { - file mkdir $::appfs::cachedir - - sqlite3 ::appfs::db [file join $::appfs::cachedir cache.db] - } - - _db eval {CREATE TABLE IF NOT EXISTS sites(hostname PRIMARY KEY, lastUpdate, ttl);} - _db eval {CREATE TABLE IF NOT EXISTS packages(hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest);} - _db eval {CREATE TABLE IF NOT EXISTS files(package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory);} - } - - proc download {hostname hash {method sha1}} { - set url "http://$hostname/appfs/$method/$hash" - set file [_cachefile $url $hash] - - if {![file exists $file]} { - return -code error "Unable to fetch" - } - - return $file - } - - proc getindex {hostname} { - set now [clock seconds] - - set lastUpdates [_db eval {SELECT lastUpdate, ttl FROM sites WHERE hostname = $hostname LIMIT 1;}] - if {[llength $lastUpdates] == 0} { - set lastUpdate 0 - set ttl 0 - } else { - set lastUpdate [lindex $lastUpdates 0] - set ttl [lindex $lastUpdates 1] - } - - if {$now < ($lastUpdate + $ttl)} { - return COMPLETE - } - - if {[string match "*\[/~\]*" $hostname]} { - return -code error "Invalid hostname" - } - - set url "http://$hostname/appfs/index" - - catch { - set token [::http::geturl $url] - if {[::http::ncode $token] == "200"} { - set indexhash_data [::http::data $token] - } - ::http::reset $token - $token cleanup - } - - if {![info exists indexhash_data]} { - # Cache this result for 60 seconds - _db eval {INSERT OR REPLACE INTO sites (hostname, lastUpdate, ttl) VALUES ($hostname, $now, $::appfs::nttl);} - - return -code error "Unable to fetch $url" - } - - set indexhash [lindex [split $indexhash_data ","] 0] - - if {![_isHash $indexhash]} { - return -code error "Invalid hash: $indexhash" - } - - set file [download $hostname $indexhash] - set fd [open $file] - set data [read $fd] - close $fd - - set curr_packages [list] - foreach line [split $data "\n"] { - set line [string trim $line] - - if {[string match "*/*" $line]} { - continue - } - - if {$line == ""} { - continue - } - - set work [split $line ","] - - unset -nocomplain pkgInfo - set pkgInfo(package) [lindex $work 0] - set pkgInfo(version) [lindex $work 1] - set pkgInfo(os) [_normalizeOS [lindex $work 2]] - set pkgInfo(cpuArch) [_normalizeCPU [lindex $work 3]] - set pkgInfo(hash) [string tolower [lindex $work 4]] - set pkgInfo(hash_type) "sha1" - set pkgInfo(isLatest) [expr {!![lindex $work 5]}] - - if {![_isHash $pkgInfo(hash)]} { - continue - } - - lappend curr_packages $pkgInfo(hash) - - # Do not do any additional work if we already have this package - set existing_packages [_db eval {SELECT package FROM packages WHERE hostname = $hostname AND sha1 = $pkgInfo(hash);}] - if {[lsearch -exact $existing_packages $pkgInfo(package)] != -1} { - continue - } - - if {$pkgInfo(isLatest)} { - _db eval {UPDATE packages SET isLatest = 0 WHERE hostname = $hostname AND package = $pkgInfo($package) AND os = $pkgInfo($package) AND cpuArch = $pkgInfo(cpuArch);} - } - - _db eval {INSERT INTO packages (hostname, sha1, package, version, os, cpuArch, isLatest, haveManifest) VALUES ($hostname, $pkgInfo(hash), $pkgInfo(package), $pkgInfo(version), $pkgInfo(os), $pkgInfo(cpuArch), $pkgInfo(isLatest), 0);} - } - - # Look for packages that have been deleted - set found_packages [_db eval {SELECT sha1 FROM packages WHERE hostname = $hostname;}] - foreach package $found_packages { - set found_packages_arr($package) 1 - } - - foreach package $curr_packages { - unset -nocomplain found_packages_arr($package) - } - - foreach package [array names found_packages_arr] { - _db eval {DELETE FROM packages WHERE hostname = $hostname AND sha1 = $package;} - } - - _db eval {INSERT OR REPLACE INTO sites (hostname, lastUpdate, ttl) VALUES ($hostname, $now, $::appfs::ttl);} - - return COMPLETE - } - - proc getpkgmanifest {hostname package_sha1} { - set haveManifests [_db eval {SELECT haveManifest FROM packages WHERE sha1 = $package_sha1 LIMIT 1;}] - set haveManifest [lindex $haveManifests 0] - - if {$haveManifest} { - return COMPLETE - } - - if {![_isHash $package_sha1]} { - return FAIL - } - - set file [download $hostname $package_sha1] - set fd [open $file] - set pkgdata [read $fd] - close $fd - - _db transaction { - foreach line [split $pkgdata "\n"] { - set line [string trim $line] - - if {$line == ""} { - continue - } - - set work [split $line ","] - - unset -nocomplain fileInfo - set fileInfo(type) [lindex $work 0] - set fileInfo(time) [lindex $work 1] - - set work [lrange $work 2 end] - switch -- $fileInfo(type) { - "file" { - set fileInfo(size) [lindex $work 0] - set fileInfo(perms) [lindex $work 1] - set fileInfo(sha1) [lindex $work 2] - - set work [lrange $work 3 end] - } - "symlink" { - set fileInfo(source) [lindex $work 0] - set work [lrange $work 1 end] - } - } - - set fileInfo(name) [join $work ","] - set fileInfo(name) [split [string trim $fileInfo(name) "/"] "/"] - set fileInfo(directory) [join [lrange $fileInfo(name) 0 end-1] "/"] - set fileInfo(name) [lindex $fileInfo(name) end] - - _db eval {INSERT INTO files (package_sha1, type, time, source, size, perms, file_sha1, file_name, file_directory) VALUES ($package_sha1, $fileInfo(type), $fileInfo(time), $fileInfo(source), $fileInfo(size), $fileInfo(perms), $fileInfo(sha1), $fileInfo(name), $fileInfo(directory) );} - _db eval {UPDATE packages SET haveManifest = 1 WHERE sha1 = $package_sha1;} - } - } - - return COMPLETE - } -} ADDED build Index: build ================================================================== --- build +++ build @@ -0,0 +1,419 @@ +#! /usr/bin/env bash + +# Set timezone to default +TZ=UTC +export TZ + +targetmode='install' +if [ "$1" == '--cpio' ]; then + targetmode='archive' + + shift +fi + +pkg="$(echo "$1" | sed 's@/*$@@;s@^\.*/*@@')" + +if [ -z "${pkg}" ]; then + echo "Usage: build [--cpio] " 2>&1 + + exit 1 +fi + +function download() { + if [ ! -e "${pkgarchive}" ]; then + # Download + ## Cleanup + rm -f src.new + + ## Fetch file + wget -O src.new "${url}" || exit 1 + + ## Verify signature + src_sha256="$(openssl sha256 'src.new' | sed 's@^.*= @@')" + if [ "${src_sha256}" != "${sha256}" ]; then + echo "SHA256 mismatch: Downloaded: ${src_sha256} != Expected: ${sha256}" >&2 + + exit 1 + fi + + ## Move file into place + mv src.new "${pkgarchive}" + fi +} + +function extract() { + local decompress + + # Decompress archive + ## Determine type of archive + case "${url}" in + *.tar.xz|*.tar.xz'?'*|*.txz) + decompress='xz' + ;; + *.tar.gz|*.tar.gz'?'*|*.tgz) + decompress='gzip' + ;; + *.tar.bz2|*.tar.bz2'?'*|*.tbz2) + decompress='bzip2' + ;; + *.zip|*.zip'?'*) + decompress='unzip' + ;; + *) + echo "Unknown compression method: ${url}" >&2 + + exit 1 + ;; + esac + + ## Do decompression + case "${decompress}" in + unzip) + unzip "${pkgarchive}" || die 'Unable to uncompress archive' + ;; + *) + "${decompress}" -dc "${pkgarchive}" | tar -xf - || die 'Unable to uncompress archive' + ;; + esac +} + +function apply_patches() { + local patch + + for patch in "${pkgdir}/patches"/*; do + if [ ! -e "${patch}" ]; then + continue + fi + + case "${patch}" in + *.diff|*.patch) + ;; + *) + continue + ;; + esac + + if [ -e "${patch}.sh" ]; then + if ! sh "${patch}.sh"; then + continue + fi + fi + + patch -p1 < "${patch}" + done +} + +function verifyRequiredPackages() { + local pkg pkgdomain pkgversion + local pkgdir pkgconfigdir pkgfound + + for pkg in "${require[@]}"; do + pkgdomain='' + pkgversion='' + pkgchanges=(CFLAGS LDFLAGS PATH PKG_CONFIG_PATH) + + case "${pkg}" in + *:*) + pkgchanges=($(echo "${pkg}" | cut -f 2 -d ':')) + pkg="$(echo "${pkg}" | cut -f 1 -d ':')" + ;; + esac + + case "${pkg}" in + */*@*) + pkgdomain="$(echo "${pkg}" | cut -f 2 -d '@')" + pkgversion="$(echo "${pkg}" | cut -f 2 -d '/' | cut -f 1 -d '@')" + pkg="$(echo "${pkg}" | cut -f 1 -d '/')" + ;; + */*) + pkgversion="$(echo "${pkg}" | cut -f 2 -d '/')" + pkg="$(echo "${pkg}" | cut -f 1 -d '/')" + ;; + *@*) + pkgdomain="$(echo "${pkg}" | cut -f 2 -d '@')" + pkg="$(echo "${pkg}" | cut -f 1 -d '@')" + ;; + esac + + if [ -z "${pkgdomain}" ]; then + pkgdomain="${domain}" + fi + + pkgfound='0' + for pkgdir in "/opt/appfs/${pkgdomain}/${pkg}/platform"/${pkgversion:-latest} "/opt/appfs/${pkgdomain}/${pkg}/platform"/${pkgversion:-*}; do + pkgconfigdir="${pkgdir}/lib/pkgconfig" + + if [ ! -d "${pkgdir}" ]; then + continue + fi + + # If the package version was unspecified, fully resolve + # the directory that we found + if [ -z "${pkgversion}" ]; then + pkgdir="$(readlink -f "${pkgdir}")" + fi + + pkgfound='1' + + for pkgchange in "${pkgchanges[@]}"; do + case "${pkgchange}" in + CFLAGS) + CFLAGS="${CFLAGS} -isystem ${pkgdir}/include" + CPPFLAGS="${CPPFLAGS} -isystem ${pkgdir}/include" + export CFLAGS CPPFLAGS + ;; + LDFLAGS) + LDFLAGS="${LDFLAGS} -L${pkgdir}/lib -Wl,-rpath,${pkgdir}/lib" + export LDFLAGS + ;; + PATH) + PATH="${PATH}:${pkgdir}/bin" + export PATH + ;; + PKG_CONFIG_PATH) + if [ -d "${pkgconfigdir}" ]; then + PKG_CONFIG_PATH="${PKG_CONFIG_PATH}:${pkgconfigdir}" + export PKG_CONFIG_PATH + fi + ;; + esac + done + + break + done + + if [ "${pkgfound}" = '0' ]; then + die "Package ${pkg}/${pkgversion:-*}@${pkgdomain} not found." + fi + done +} + +function verifyPrerequisites() { + : +} + +function determineOsArch() { + os="$(uname -s | dd conv=lcase 2>/dev/null)" + arch="$(uname -m | dd conv=lcase 2>/dev/null)" + + case "${arch}" in + i?86) + arch='ix86' + ;; + esac +} + +function determinePrefix() { + determineOsArch + + prefixsuffix="${pkg}/${os}-${arch}/${version}" + prefix="/opt/appfs/${domain}/${prefixsuffix}" + destdir="$(pwd)/INST" + + mkdir "${destdir}" || die +} + +function preconfigure() { + : +} + +function postconfigure() { + : +} + +function configure_gcc() { + local glibcdir linuxheadersdir + local dynlinker + local gcc_default_headers + + glibcdir="/opt/appfs/core.appfs.rkeene.org/glibc/platform/latest" + glibcdir="$(readlink -f "${glibcdir}")" + + linuxheadersdir="/opt/appfs/core.appfs.rkeene.org/linux-headers/platform/latest" + linuxheadersdir="$(readlink -f "${linuxheadersdir}")" + + dynlinker="$(ls "${glibcdir}"/lib/ld-linux*.so.* | tail -n 1)" + + if [ ! -f "${dynlinker}" ]; then + die 'glibc directory is not available (appfs running/working?)' + fi + + gcc_default_headers="$(echo '' | ${CPP:-cpp} -v 2>&1 | sed '/^End of search list/,$ d;0,/search starts here:$/ d' | grep '/gcc/' | sed 's@^ *@-isystem @' | tr $'\n' ' ')" + + CC="${CC:-gcc} -nostdinc ${gcc_default_headers} -isystem ${glibcdir}/include" + CXX="${CXX:-g++} -nostdinc ${gcc_default_headers} -isystem ${glibcdir}/include" + + if ! echo " ${require[*]} " | grep ' linux-headers[/@: ]' >/dev/null; then + CC="${CC} -isystem ${linuxheadersdir}/include" + CXX="${CXX} -isystem ${linuxheadersdir}/include" + fi + + BUILD_CC="${CC}" + HOST_CC="${CC}" + + LDFLAGS="${LDFLAGS} -L${glibcdir}/lib -Wl,-rpath,${glibcdir}/lib -Wl,--dynamic-linker,${dynlinker}" + if [ -z "${appfs_build_no_default_symver}" ]; then + LDFLAGS="${LDFLAGS} -Wl,--default-symver" + fi + + PKG_CONFIG_LIBDIR="${glibcdir}/lib/pkgconfig" + + export CC BUILD_CC HOST_CC LDFLAGS PKG_CONFIG_LIBDIR +} + +function configure() { + configure_gcc + ./configure --prefix="${prefix}" --sysconfdir="${prefix}/etc" --libdir="${prefix}/lib" --localstatedir=/var "${configure_extra[@]}" +} + +function prebuild() { + : +} + +function postbuild() { + : +} + +function build() { + grep "DESTDIR" Makefile >/dev/null || die "Don't know how to build this software" + + make "${make_extra[@]}" +} + +function preinstall() { + : +} + +function postinstall() { + : +} + +function install() { + make install DESTDIR="${destdir}" +} + +function cleanup() { + cd "${workdir}" || exit 1 + cd .. || exit 1 + rm -rf "${workdir}" +} + +function die() { + local message + + message="$1" + + if [ -n "${message}" ]; then + echo "error: ${message}" >&2 + fi + + exit 1 +} + +scriptdir="$(cd "$(dirname "$(which "$0")")" && pwd)" +if [ -z "${scriptdir}" ]; then + echo "Unable to locate script directory" >&2 + + exit 1 +fi + +cd "${scriptdir}" || exit 1 + +if [ -f 'build.conf' ]; then + . 'build.conf' +fi + +if [ -d "pkgs/${pkg}" ]; then + pkgdir="$(pwd)/pkgs/${pkg}" + pkgfile="${pkgdir}/info" +else + pkgfile="$(pwd)/pkgs/${pkg}" + pkgdir="${pkgfile}" +fi + +if [ ! -e "${pkgfile}" ]; then + echo "Invalid package." >&2 + + exit 1 +fi + +pkgdate="$(for artifact in $(find "${pkgdir}" -type f -print0 | xargs -n 1 -0 fossil finfo --limit 1 --width 0 2>/dev/null | grep '^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] ' | sed 's@^[^ ]* \[@@;s@\].*@@' | sort -u); do fossil info "${artifact}" | awk '/^uuid:/{ print $3 $4 }' | sed 's@[-:]@@g;s@..$@\.&@'; done | sort -n | tail -n 1)" +if [ -z "${pkgdate}" ]; then + pkgdate="$(find "${pkgdir}" -type f -printf '%TY%Tm%Td%TH%TM.%TS\n' 2>/dev/null | cut -f 1-2 -d '.' | sort -n | tail -n 1)" +fi + +. "${pkgfile}" + +archivedir="$(pwd)/ARCHIVE" +workdir="workdir-$$${RANDOM}${RANDOM}${RANDOM}" +pkgarchive="${archivedir}/${pkg}-${version}" +mkdir "${archivedir}" >/dev/null 2>/dev/null +mkdir "${workdir}" || exit 1 +cd "${workdir}" || exit 1 +workdir="$(pwd)" + +# Download +download + +# Extract +extract + +# If we just have one directory, use that directory +dir="$(echo *)" +if [ -e "${dir}" ]; then + mv "${dir}"/* . +fi + +# Verify pre-requisites are met +verifyRequiredPackages || die 'Required packages missing' +verifyPrerequisites || die 'Prerequisities failed' + +# Start logging +set -x + +# Determine properties +determinePrefix + +# Apply patches +apply_patches + +# Start the build +preconfigure || die 'preconfigure failed' +configure || die 'configure failed' +postconfigure || die 'postconfigure failed' + +prebuild || die 'prebuild failed' +build || die 'build failed' +postbuild || die 'postbuild failed' + +preinstall || die 'preinstall failed' +install || die 'install failed' +postinstall || die 'postinstall failed' + +( + case "${targetmode}" in + install) + appdir="$(appfsinstalldir)/${prefixsuffix}" + mkdir -p "${appdir}" + + cd "${destdir}/${prefix}" || exit 1 + + cp -rp * "${appdir}" + find "${appdir}" -print0 | xargs -0 touch -t "${pkgdate}" + find "${appdir}" -print0 | xargs -0 touch -m -t "${pkgdate}" + find "${appdir}" -print0 | xargs -0 touch -a -t "${pkgdate}" + ;; + archive) + archivefile="${scriptdir}/${pkg}-${version}-$(echo "${pkgdate}" | sed 's@\.@@g')-${os}-${arch}-${domain}.cpio" + cd "${destdir}/${prefix}/../../.." || exit 1 + find "${prefixsuffix}" -print0 | xargs -0 touch -t "${pkgdate}" + find "${prefixsuffix}" -print0 | xargs -0 touch -m -t "${pkgdate}" + find "${prefixsuffix}" -print0 | xargs -0 touch -a -t "${pkgdate}" + find "${prefixsuffix}" | sort | cpio --owner 0:0 -H newc -o > "${archivefile}" + ;; + esac +) || die 'final installation failed' + +cleanup + +exit 0 ADDED build.conf Index: build.conf ================================================================== --- build.conf +++ build.conf @@ -0,0 +1,14 @@ +domain=rkeene.org +function appfsinstalldir() { + case "${domain}" in + rkeene.org) + echo "/web/rkeene/appfs/applications" + ;; + appfs.rkeene.org) + echo "/web/customers/appfs.rkeene.org/appfs/applications" + ;; + core.appfs.rkeene.org) + echo "/web/static/core.appfs.rkeene.org/appfs/applications" + ;; + esac +} ADDED pkgs/acl Index: pkgs/acl ================================================================== --- pkgs/acl +++ pkgs/acl @@ -0,0 +1,21 @@ +#! /usr/bin/env bash + +version='2.2.52' +url="http://download.savannah.gnu.org/releases/acl/acl-${version}.src.tar.gz" +domain=core.appfs.rkeene.org +sha256='179074bb0580c06c4b4137be4c5a92a701583277967acdb5546043c7874e0d23' +require=(attr) + +function prebuild() { + echo "# Ignore: DESTDIR" >> Makefile +} + +function install() { + make install install-dev install-lib DESTDIR="${destdir}" +} + +function postinstall() { + rm -f "${destdir}/${prefix}/libexec/libacl.so" + mv "${destdir}/${prefix}"/libexec/* "${destdir}/${prefix}/lib/" + rm -rf "${destdir}/${prefix}/libexec" +} ADDED pkgs/attr/info Index: pkgs/attr/info ================================================================== --- pkgs/attr/info +++ pkgs/attr/info @@ -0,0 +1,14 @@ +#! /usr/bin/env bash + +version='2.4.47' +url="http://download.savannah.gnu.org/releases/attr/attr-${version}.src.tar.gz" +domain=core.appfs.rkeene.org +sha256='25772f653ac5b2e3ceeb89df50e4688891e21f723c460636548971652af0a859' + +function prebuild() { + echo "# Ignore: DESTDIR" >> Makefile +} + +function install() { + make install install-dev install-lib DESTDIR="${destdir}" +} ADDED pkgs/attr/patches/attr.destdir.diff Index: pkgs/attr/patches/attr.destdir.diff ================================================================== --- pkgs/attr/patches/attr.destdir.diff +++ pkgs/attr/patches/attr.destdir.diff @@ -0,0 +1,36 @@ +--- ./include/builddefs.in.orig 2011-04-08 11:56:59.000000000 -0500 ++++ ./include/builddefs.in 2011-04-18 13:27:35.000000000 -0500 +@@ -40,14 +40,14 @@ + PKG_VERSION = @pkg_version@ + PKG_PLATFORM = @pkg_platform@ + PKG_DISTRIBUTION= @pkg_distribution@ +-PKG_BIN_DIR = @bindir@ +-PKG_SBIN_DIR = @sbindir@ +-PKG_LIB_DIR = @libdir@@libdirsuffix@ +-PKG_DEVLIB_DIR = @libexecdir@@libdirsuffix@ +-PKG_INC_DIR = @includedir@/attr +-PKG_MAN_DIR = @mandir@ +-PKG_DOC_DIR = @datadir@/doc/@pkg_name@ +-PKG_LOCALE_DIR = @datadir@/locale ++PKG_BIN_DIR = $(DESTDIR)@bindir@ ++PKG_SBIN_DIR = $(DESTDIR)@sbindir@ ++PKG_LIB_DIR = $(DESTDIR)@libdir@@libdirsuffix@ ++PKG_DEVLIB_DIR = $(DESTDIR)@libexecdir@@libdirsuffix@ ++PKG_INC_DIR = $(DESTDIR)@includedir@/attr ++PKG_MAN_DIR = $(DESTDIR)@mandir@ ++PKG_DOC_DIR = $(DESTDIR)@datadir@/doc/@pkg_name@ ++PKG_LOCALE_DIR = $(DESTDIR)@datadir@/locale + + CC = @cc@ + AWK = @awk@ +--- ./include/buildmacros.orig 2011-04-08 11:56:59.000000000 -0500 ++++ ./include/buildmacros 2011-04-18 13:28:23.000000000 -0500 +@@ -40,7 +40,7 @@ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +-INSTALL = $(TOPDIR)/include/install-sh -o $(PKG_USER) -g $(PKG_GROUP) ++INSTALL = $(TOPDIR)/include/install-sh + + SHELL = /bin/sh + IMAGES_DIR = $(TOPDIR)/all-images ADDED pkgs/bash Index: pkgs/bash ================================================================== --- pkgs/bash +++ pkgs/bash @@ -0,0 +1,7 @@ +#! /usr/bin/env bash + +version='4.3.30' +url="http://ftp.gnu.org/gnu/bash/bash-${version}.tar.gz" +domain=core.appfs.rkeene.org +sha256='317881019bbf2262fb814b7dd8e40632d13c3608d2f237800a8828fbb8a640dd' +require=(zlib readline ncurses) ADDED pkgs/binutils Index: pkgs/binutils ================================================================== --- pkgs/binutils +++ pkgs/binutils @@ -0,0 +1,7 @@ +#! /usr/bin/env bash + +version=2.24 +url="http://ftp.gnu.org/gnu/binutils/binutils-2.24.tar.gz" +domain=core.appfs.rkeene.org +sha256='4930b2886309112c00a279483eaef2f0f8e1b1b62010e0239c16b22af7c346d4' +require=(zlib) ADDED pkgs/bzip2 Index: pkgs/bzip2 ================================================================== --- pkgs/bzip2 +++ pkgs/bzip2 @@ -0,0 +1,39 @@ +#! /usr/bin/env bash + +version=1.0.6 +url="http://www.bzip.org/${version}/bzip2-${version}.tar.gz" +sha256="a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd" +domain='core.appfs.rkeene.org' +require=() + +function configure() { + configure_gcc + cat Makefile-libbz2_so | sed "s|CC=gcc|CC=${CC} ${CFLAGS} ${LDFLAGS}|g" > Makefile-libbz2_so.new + cat Makefile | sed "s|LDFLAGS=|LDFLAGS=${LDFLAGS}|g" | sed "s|CFLAGS=|CFLAGS=${CFLAGS} |g" > Makefile.new + mv -f Makefile-libbz2_so.new Makefile-libbz2_so + mv -f Makefile.new Makefile +} + +function build() { + make -f Makefile-libbz2_so PREFIX="${prefix}" +} + +function install() { + make install PREFIX="${destdir}/${prefix}" + mv libbz2*.so* ${destdir}/${prefix}/lib + ( + cd "${destdir}/${prefix}/bin" || exit 1 + rm -f bzcmp bzegrep bzfgrep bzless + ln -s bzdiff bzcmp + ln -s bzgrep bzegrep + ln -s bzgrep bzfgrep + ln -s bzmore bzless + ) || return 1 + + ( + cd "${destdir}/${prefix}/lib" || exit 1 + rm -f bzcmp bzegrep bzfgrep bzless + ln -s libbz2.so.1.0 libbz2.so.1 + ln -s libbz2.so.1 libbz2.so + ) || return 1 +} ADDED pkgs/coreutils Index: pkgs/coreutils ================================================================== --- pkgs/coreutils +++ pkgs/coreutils @@ -0,0 +1,13 @@ +#! /usr/bin/env bash + +version='8.23' +url="http://ftp.gnu.org/gnu/coreutils/coreutils-${version}.tar.xz" +domain=core.appfs.rkeene.org +sha256='ec43ca5bcfc62242accb46b7f121f6b684ee21ecd7d075059bf650ff9e37b82d' +require=(attr acl libcap) +configure_extra=(--without-gmp) + +function preconfigure() { + DEFAULT_POSIX2_VERSION=199209 + export DEFAULT_POSIX2_VERSION +} ADDED pkgs/dact Index: pkgs/dact ================================================================== --- pkgs/dact +++ pkgs/dact @@ -0,0 +1,21 @@ +#! /usr/bin/env bash + +version='0.8.42' +url="http://www.rkeene.org/devel/dact-${version}.tar.gz" +sha256='08c91d36b2de30c4f2e9e13a7b044c137c096db2ba8d868d1962e209dd6b2ed8' +domain='rkeene.org' +require=(zlib@core.appfs.rkeene.org bzip2@core.appfs.rkeene.org) + +function preconfigure() { + sed -i -r 's/^(prefix|libdir|sysconfdir) *= */&$(DESTDIR)/g' Makefile.in + sed -i '/^ALGO *=/ a \ +MODS = $(ALGO:.c=.so)' Makefile.in +} + +function postinstall() { + # Delete incomplete "libdact" + rm -f "${destdir}/${prefix}"/lib/libdact* + rmdir "${destdir}/${prefix}/lib" >/dev/null 2>/dev/null + + return 0 +} ADDED pkgs/ffmpeg Index: pkgs/ffmpeg ================================================================== --- pkgs/ffmpeg +++ pkgs/ffmpeg @@ -0,0 +1,15 @@ +#! /usr/bin/env bash + +version='2.4.3' +url="https://www.ffmpeg.org/releases/ffmpeg-${version}.tar.bz2" +domain=rkeene.org +sha256='ca5c3e3c0e4f9e43b9dceafceb866acb1ea575cb9f2d94e0d959303e4fc4e602' +require=(zlib@core.appfs.rkeene.org readline@core.appfs.rkeene.org) +make_extra=(-j10) + +function configure() { + configure_gcc + CC="$(echo "${CC}" | sed 's@ -nostdinc @ @g')" + ./configure --prefix="${prefix}" --cc="${CC} ${CPPFLAGS}" --extra-cflags="${CFLAGS}" --host-cppflags="${CPPFLAGS}" --extra-ldflags="${LDFLAGS}" --enable-shared --enable-pic --enable-rpath --enable-x11grab --enable-gpl || return 1 + echo '# Ignore: DESTDIR' >> Makefile +} ADDED pkgs/filed Index: pkgs/filed ================================================================== --- pkgs/filed +++ pkgs/filed @@ -0,0 +1,18 @@ +#! /usr/bin/env bash + +version='1.12' +url="http://filed.rkeene.org/fossil/tarball/filed-${version}.tar.gz?uuid=${version}" +sha256='807931f6c8ab4c90e26f5221e89558a84b31d4b4ce60c8c2cccb09350e25de85' +domain='rkeene.org' + +function configure() { + configure_gcc +} + +function build() { + make prefix="${prefix}" CC="${CC} ${CFLAGS}" LDFLAGS="-pthread ${LDFLAGS}" +} + +function install() { + make install prefix="${prefix}" DESTDIR="${destdir}" +} ADDED pkgs/fossil Index: pkgs/fossil ================================================================== --- pkgs/fossil +++ pkgs/fossil @@ -0,0 +1,25 @@ +#! /usr/bin/env bash + +version='1.32' +url="https://www.fossil-scm.org/download/fossil-src-${version}.tar.gz" +sha256='cd79c333eb9e86fbb8c17bf5cdf31c387e4ab768eede623aed21adfdbcad686e' +require=(zlib@core.appfs.rkeene.org) + +function configure() { + configure_gcc + + CCACHE=none + export CCACHE + + ./configure "${configure_extra[@]}" +} + +function build() { + make +} + +function install() { + mkdir -p "${destdir}/${prefix}/bin" + cp fossil "${destdir}/${prefix}/bin/" + chmod 755 "${destdir}/${prefix}/bin/fossil" +} ADDED pkgs/gcc Index: pkgs/gcc ================================================================== --- pkgs/gcc +++ pkgs/gcc @@ -0,0 +1,8 @@ +#! /usr/bin/env bash + +version=4.9.2 +url="http://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.gz" +domain=core.appfs.rkeene.org +sha256='3e573826ec8b0d62d47821408fbc58721cd020df3e594cd492508de487a43b5e' +require=(zlib binutils:PATH linux-headers/2.6.32.63) +configure_extra=(--disable-multilib) ADDED pkgs/glibc Index: pkgs/glibc ================================================================== --- pkgs/glibc +++ pkgs/glibc @@ -0,0 +1,15 @@ +#! /usr/bin/env bash + +version=2.20 +url="http://ftp.gnu.org/gnu/glibc/glibc-${version}.tar.xz" +domain=core.appfs.rkeene.org +sha256='f84b6d42aecc288d593c397b0a3d02260a33ee686bce0c634eb9b32798f36ba5' + +function configure() { + mkdir BUILD + cd BUILD + + ../configure --prefix="${prefix}" --sysconfdir=/etc --localstatedir=/var || return 1 + + echo '# Ignore: DESTDIR' >> Makefile +} ADDED pkgs/gmp Index: pkgs/gmp ================================================================== --- pkgs/gmp +++ pkgs/gmp @@ -0,0 +1,10 @@ +#! /usr/bin/env bash + +version='6.0.0a' +url="http://ftp.gnu.org/gnu/gmp/gmp-6.0.0a.tar.xz" +domain=core.appfs.rkeene.org +sha256='9156d32edac6955bc53b0218f5f3763facb890b73a835d5e1b901dcf8eb8b764' + +function postinstall() { + rm -f "${destdir}/${prefix}/share/info/dir" +} ADDED pkgs/libcap Index: pkgs/libcap ================================================================== --- pkgs/libcap +++ pkgs/libcap @@ -0,0 +1,19 @@ +#! /usr/bin/env bash + +version='2.24' +url="http://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-${version}.tar.xz" +domain=core.appfs.rkeene.org +sha256='cee4568f78dc851d726fc93f25f4ed91cc223b1fe8259daa4a77158d174e6c65' +require=(attr) + +function configure() { + : +} + +function build() { + make prefix="${prefix}" lib='lib' +} + +function install() { + make prefix="${prefix}" lib='lib' DESTDIR="${destdir}" RAISE_SETFCAP='no' install +} ADDED pkgs/linux-headers Index: pkgs/linux-headers ================================================================== --- pkgs/linux-headers +++ pkgs/linux-headers @@ -0,0 +1,18 @@ +#! /usr/bin/env bash + +version='3.17.2' +url="https://www.kernel.org/pub/linux/kernel/v3.x/linux-${version}.tar.xz" +domain=core.appfs.rkeene.org +sha256='f9221dc0878955318ab57b8bb5ea1f26cbbaa39359c91d0f6c8de74d68aea796' + +function configure() { + : +} + +function build() { + make defconfig || die +} + +function install() { + make INSTALL_HDR_PATH="${destdir}/${prefix}" headers_install || die +} ADDED pkgs/mpc Index: pkgs/mpc ================================================================== --- pkgs/mpc +++ pkgs/mpc @@ -0,0 +1,7 @@ +#! /usr/bin/env bash + +version='1.0.2' +url="http://ftp.gnu.org/gnu/mpc/mpc-${version}.tar.gz" +domain=core.appfs.rkeene.org +sha256='b561f54d8a479cee3bc891ee52735f18ff86712ba30f036f8b8537bae380c488' +require=(gmp mpfr) ADDED pkgs/mpfr Index: pkgs/mpfr ================================================================== --- pkgs/mpfr +++ pkgs/mpfr @@ -0,0 +1,7 @@ +#! /usr/bin/env bash + +version='3.1.2' +url="http://ftp.gnu.org/gnu/mpfr/mpfr-${version}.tar.xz" +domain=core.appfs.rkeene.org +sha256='399d0f47ef6608cc01d29ed1b99c7faff36d9994c45f36f41ba250147100453b' +require=(gmp) ADDED pkgs/ncurses Index: pkgs/ncurses ================================================================== --- pkgs/ncurses +++ pkgs/ncurses @@ -0,0 +1,20 @@ +#! /usr/bin/env bash + +version='5.9' +url="http://ftp.gnu.org/gnu/ncurses/ncurses-${version}.tar.gz" +domain=core.appfs.rkeene.org +sha256='9046298fb440324c9d4135ecea7879ffed8546dd1b58e59430ea07a4633f563b' +configure_extra=(--with-termlib --with-ticlib --with-shared) + +function postinstall() { + # Create libtermcap compatability + ## Create libtermcap.so shared object + cat << \_EOF_ > "${destdir}/${prefix}/lib/libtermcap.so" +GROUP( libtinfo.so ) +_EOF_ + + ## Create termcap.h header + cat << \_EOF_ > "${destdir}/${prefix}/include/termcap.h" +#include +_EOF_ +} ADDED pkgs/readline Index: pkgs/readline ================================================================== --- pkgs/readline +++ pkgs/readline @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +version=6.3 +url="https://ftp.gnu.org/gnu/readline/readline-${version}.tar.gz" +domain=core.appfs.rkeene.org +sha256='56ba6071b9462f980c5a72ab0023893b65ba6debb4eeb475d7a563dc65cafd43' ADDED pkgs/tcl Index: pkgs/tcl ================================================================== --- pkgs/tcl +++ pkgs/tcl @@ -0,0 +1,15 @@ +#! /usr/bin/env bash + +version='8.6.3' +url="http://sourceforge.net/projects/tcl/files/Tcl/${version}/tcl${version}-src.tar.gz" +domain=core.appfs.rkeene.org +sha256='6ce0778de0d50daaa9c345d7c1fd1288fb658f674028812e7eeee992e3051005' +require=(zlib) + +function preconfigure() { + cd unix +} + +function postinstall() { + cd .. +} ADDED pkgs/zlib Index: pkgs/zlib ================================================================== --- pkgs/zlib +++ pkgs/zlib @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +version=1.2.8 +url="http://zlib.net/zlib-${version}.tar.gz" +domain=core.appfs.rkeene.org +sha256='36658cb768a54c1d4dec43c3116c27ed893e88b02ecfcb44f2166f9c0b7f2a0d'