aboutsummaryrefslogtreecommitdiff
path: root/snag
diff options
context:
space:
mode:
Diffstat (limited to 'snag')
-rwxr-xr-xsnag/configure8
-rwxr-xr-xsnag/scripts/get_pkg_attrs.sh4
-rw-r--r--snag/src/download_db.c101
-rw-r--r--snag/src/download_db.h10
-rw-r--r--snag/src/main.c7
-rw-r--r--snag/src/package.h7
-rw-r--r--snag/src/package_db.c6
-rw-r--r--snag/src/package_db.h4
-rw-r--r--snag/src/util.c14
-rw-r--r--snag/src/util.h6
10 files changed, 149 insertions, 18 deletions
diff --git a/snag/configure b/snag/configure
index 757df3a..3048f71 100755
--- a/snag/configure
+++ b/snag/configure
@@ -1,7 +1,7 @@
#!/bin/bash
bin="snag"
-libs=""
+libs="libcurl libcrypto"
builddir="build"
PREFIX="/usr"
@@ -19,17 +19,17 @@ CFLAGS_DEBUG="$CFLAGS -Wall -g -DDEBUG=1"
write() { echo "$@" >> build.ninja; }
-echo "$CFLAGS_DEBUG $(pkg-config --cflags $libs 2>/dev/null)" | tr ' ' '\n' > compile_flags.txt
+echo "$CFLAGS_DEBUG $(pkg-config --cflags $libs)" | tr ' ' '\n' > compile_flags.txt
rm -f build.ninja
write "builddir = $builddir"
-write "libs = $(pkg-config --libs $libs 2>/dev/null)"
+write "libs = $(pkg-config --libs $libs)"
write 'rule link'
write ' description = LD $out'
write ' command = gcc $libs $in -o $out'
for target in $(echo "debug release"); do
- eval write "cflags_$target = \$CFLAGS_${target^^} $(pkg-config --cflags $libs 2>/dev/null)"
+ eval write "cflags_$target = \$CFLAGS_${target^^} $(pkg-config --cflags $libs)"
write "rule cc-$target"
write ' deps = gcc'
diff --git a/snag/scripts/get_pkg_attrs.sh b/snag/scripts/get_pkg_attrs.sh
index 932c79c..8c505b5 100755
--- a/snag/scripts/get_pkg_attrs.sh
+++ b/snag/scripts/get_pkg_attrs.sh
@@ -13,7 +13,7 @@ fi
. $1
# output package attributes (type char, value, null delimiter)
-echoatt() { [ -n "$2" ] && printf "$1$2\0"; }
+echoatt() { [ -n "$2" ] && printf "$1$2\0"; return 0; }
echoatt i "$pkg_id"
echoatt n "$pkg_name"
echoatt d "$pkg_desc"
@@ -21,4 +21,4 @@ echoatt w "$pkg_webpage"
echoatt l "$pkg_license"
echoatt v "$pkg_version"
echoatt u "$pkg_source_url"
-echoatt h "$pkg_source_hash"
+echoatt c "$pkg_source_checksum"
diff --git a/snag/src/download_db.c b/snag/src/download_db.c
new file mode 100644
index 0000000..3f51347
--- /dev/null
+++ b/snag/src/download_db.c
@@ -0,0 +1,101 @@
+#include "download_db.h"
+
+#include "util.h"
+
+#include <curl/curl.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <string.h>
+#include <errno.h>
+
+// curl context
+CURL *curl = NULL;
+
+// libcrpyto context
+EVP_MD_CTX *mdctx = NULL;
+const EVP_MD *md = NULL;
+
+static size_t curl_write_cb(char* ptr, size_t size, size_t nmemb, void* usrdata)
+{
+ // write the curl data to the file in usr data
+ size_t written = fwrite(ptr, size, nmemb, (FILE *)usrdata);
+
+ // update the hash with the new data
+ EVP_DigestUpdate(mdctx, ptr, written);
+
+ return written;
+}
+
+bool download_package(package_info_t* pkg) {
+
+ if (curl == NULL) {
+ // initialize curl if it isn't already
+ CURLcode result = curl_global_init(CURL_GLOBAL_ALL);
+ if (result != CURLE_OK) die("failed to initialize curl: %s", curl_easy_strerror(result));
+ curl = curl_easy_init(); // note(jqj): for now we reuse one easy curl object
+ if (curl == NULL) die("failed to initialize easy curl");
+
+ /* come back to this if we have init and deinit */
+ /* curl_easy_cleanup(curl); */
+ /* curl_global_cleanup(); */
+ }
+
+ if (mdctx == NULL) {
+ // initialize libcrypto context if it isn't already
+ mdctx = EVP_MD_CTX_new();
+ md = EVP_sha256();
+
+ /* come back to this if we have init and deinit */
+ /* EVP_MD_CTX_free(mdctx); */
+ }
+
+ // initialize up sha256 hash
+ EVP_DigestInit_ex(mdctx, md, NULL);
+
+ // open file for writing and give it to the curl callback
+ // todo(jqj): get actual path with name
+ char* download_path = "download.tar.gz";
+ FILE* download_file = fopen(download_path, "wb");
+ if (download_file == NULL) die("failed open download file for writing (%s): %s", download_path, strerror(errno));
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_cb);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, download_file);
+
+ // make curl request
+ // callback writes to the file and feeds the hash
+ curl_easy_setopt(curl, CURLOPT_URL, pkg->attrs.source_url);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ CURLcode result = curl_easy_perform(curl);
+ if(result != CURLE_OK) {
+ log("failed to download package with curl: %s", curl_easy_strerror(result));
+ return false;
+ }
+
+ // get sha256 hash
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ unsigned int hash_len;
+ EVP_DigestFinal_ex(mdctx, hash, &hash_len);
+
+ // get hexadecimal string of sha256 hash
+ char hash_hex[SHA256_DIGEST_LENGTH * 2 + 1];
+ for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ sprintf(hash_hex + i*2,"%02x", hash[i]);
+ }
+ hash_hex[SHA256_DIGEST_LENGTH * 2] = '\0';
+
+ // confirm that hash matches checksum
+ if (pkg->attrs.source_checksum != NULL) {
+ if (strcmp(pkg->attrs.source_checksum, hash_hex) == 0) {
+ print("checksum verified for %s: %s\n", pkg->attrs.id, hash_hex);
+ return true;
+ } else {
+ log("FAIL: bad checksum for %s: %s\n", pkg->attrs.id, hash_hex);
+ return false;
+ }
+ } else {
+ // todo(jqj): not sure if we will allow packages without hashes yet
+ log("WARNING: could not verify checksum for %s download because none was provided\n", pkg->attrs.id);
+ return true;
+ }
+
+ return true;
+}
diff --git a/snag/src/download_db.h b/snag/src/download_db.h
new file mode 100644
index 0000000..fbf7b03
--- /dev/null
+++ b/snag/src/download_db.h
@@ -0,0 +1,10 @@
+#ifndef DOWNLOAD_DB_H
+#define DOWNLOAD_DB_H
+
+#include <stdbool.h>
+
+#include "package.h"
+
+bool download_package(package_info_t* pkg);
+
+#endif
diff --git a/snag/src/main.c b/snag/src/main.c
index 7d5ea58..0813032 100644
--- a/snag/src/main.c
+++ b/snag/src/main.c
@@ -1,8 +1,8 @@
-#include <stdio.h>
+#include "libargs/args.h"
#include "util.h"
-#include "libargs/args.h"
#include "package_db.h"
+#include "download_db.h"
int cmd_install(char* cmd_name, ArgParser* parser);
@@ -43,8 +43,9 @@ int cmd_install(char* cmd_name, ArgParser* parser) {
char* pkgid = ap_get_arg_at_index(parser, i);
package_info_t info;
if (load_package_info(pkgid, &info)) {
- print("Installing %s - %s\n", info.attrs.name, info.attrs.desc);
print("Downloading '%s'\n", info.attrs.source_url);
+ download_package(&info);
+ print("Installing %s - %s\n", info.attrs.name, info.attrs.desc);
run_package_install(&info);
}
}
diff --git a/snag/src/package.h b/snag/src/package.h
index 3ff58b6..b848ce6 100644
--- a/snag/src/package.h
+++ b/snag/src/package.h
@@ -1,3 +1,6 @@
+#ifndef PACKAGE_H
+#define PACKAGE_H
+
typedef struct {
char* id;
char* name;
@@ -6,7 +9,7 @@ typedef struct {
char* license;
char* version;
char* source_url;
- char* source_hash;
+ char* source_checksum;
char buffer[4069];
} package_attrs_t;
@@ -14,3 +17,5 @@ typedef struct {
char* script_path;
package_attrs_t attrs;
} package_info_t;
+
+#endif
diff --git a/snag/src/package_db.c b/snag/src/package_db.c
index 0bae257..3974120 100644
--- a/snag/src/package_db.c
+++ b/snag/src/package_db.c
@@ -80,7 +80,7 @@ bool load_package_info(char* pkgid, package_info_t* info) {
// wait for child to finish
int wstatus;
if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno));
- if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute get_pkg_attr script");
+ if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute get_pkg_attr script: %d", WEXITSTATUS(wstatus));
// read all bytes from pipe into attr buffer
ssize_t bytes_read = read(pipefds[0], info->attrs.buffer, sizeof(info->attrs.buffer));
@@ -108,8 +108,8 @@ bool load_package_info(char* pkgid, package_info_t* info) {
info->attrs.version = &info->attrs.buffer[i]; break;
case 'u':
info->attrs.source_url = &info->attrs.buffer[i]; break;
- case 'h':
- info->attrs.source_hash = &info->attrs.buffer[i]; break;
+ case 'c':
+ info->attrs.source_checksum = &info->attrs.buffer[i]; break;
}
for(;info->attrs.buffer[i] && i < bytes_read; i++);
i++;
diff --git a/snag/src/package_db.h b/snag/src/package_db.h
index bae1cdd..17ff58d 100644
--- a/snag/src/package_db.h
+++ b/snag/src/package_db.h
@@ -1,5 +1,5 @@
-#ifndef PKG_DB_H
-#define PKG_DB_H
+#ifndef PACKAGE_DB_H
+#define PACKAGE_DB_H
#include <stdbool.h>
diff --git a/snag/src/util.c b/snag/src/util.c
index 8cc9b18..e79fd34 100644
--- a/snag/src/util.c
+++ b/snag/src/util.c
@@ -45,6 +45,20 @@ void* _emalloc(int line, const char* file, size_t size, char* alloc_reason) {
}
#endif
+void printout(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+}
+
+void print(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
char* vastrcat_(int dummy, ...) {
va_list args;
diff --git a/snag/src/util.h b/snag/src/util.h
index eca4e4d..1a05ab0 100644
--- a/snag/src/util.h
+++ b/snag/src/util.h
@@ -20,9 +20,9 @@
void* _emalloc(int line, const char* file, size_t size, char* alloc_reason);
#endif
-// functions for outputting and displaying text
-#define printout(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__)
-#define print(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
+// functions for outputting and displaying text, log is used for nonroutine bad things
+void printout(const char* format, ...) __attribute__((format(printf, 1, 2)));
+void print(const char* format, ...) __attribute__((format(printf, 1, 2)));
// string functions
#define vastrcat(...) vastrcat_(0, __VA_ARGS__, NULL)