diff --git a/TODO b/TODO index 953d4a1..ce9b485 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,6 @@ - index/package fetching from URLs - read from config file - cache .apks on USB stick when using network repo for reboot -- Installation of .APK files not in any repository - Error handling and rollback - Dependency manipulation API: deletion, overwrite, check compatibility diff --git a/src/Makefile b/src/Makefile index fbb3b5b..b6c0338 100644 --- a/src/Makefile +++ b/src/Makefile @@ -16,6 +16,7 @@ apk_OBJS = \ archive.o \ version.o \ io.o \ + url.o \ gunzip.o \ blob.o \ hash.o \ diff --git a/src/apk_io.h b/src/apk_io.h index 96dc7c9..d9522f6 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -42,11 +42,14 @@ struct apk_istream *apk_gunzip_bstream(struct apk_bstream *); struct apk_istream *apk_istream_from_fd(int fd); struct apk_istream *apk_istream_from_file(const char *file); +struct apk_istream *apk_istream_from_url(const char *url); size_t apk_istream_skip(struct apk_istream *istream, size_t size); size_t apk_istream_splice(void *stream, int fd, size_t size); struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream); struct apk_bstream *apk_bstream_from_fd(int fd); +struct apk_bstream *apk_bstream_from_file(const char *file); +struct apk_bstream *apk_bstream_from_url(const char *url); struct apk_istream *apk_istream_from_file_gz(const char *file); diff --git a/src/database.c b/src/database.c index 261011c..c30550b 100644 --- a/src/database.c +++ b/src/database.c @@ -840,7 +840,7 @@ int apk_db_install_pkg(struct apk_database *db, struct install_ctx ctx; csum_t csum; char file[256]; - int fd, r; + int r; if (fchdir(db->root_fd) < 0) return errno; @@ -866,22 +866,15 @@ int apk_db_install_pkg(struct apk_database *db, snprintf(file, sizeof(file), "%s/%s-%s.apk", db->repos[0].url, newpkg->name->name, newpkg->version); - - fd = open(file, O_RDONLY); + bs = apk_bstream_from_url(file); } else - fd = open(newpkg->filename, O_RDONLY); + bs = apk_bstream_from_file(newpkg->filename); - if (fd < 0) { + if (bs == NULL) { apk_error("%s: %s", file, strerror(errno)); return errno; } - fcntl(fd, F_SETFD, FD_CLOEXEC); - - bs = apk_bstream_from_fd(fd); - if (bs == NULL) - goto err_close; - ctx = (struct install_ctx) { .db = db, .pkg = newpkg, @@ -909,8 +902,7 @@ int apk_db_install_pkg(struct apk_database *db, write(STDOUT_FILENO, ".", 1); } return r; - err_close: - close(fd); + bs->close(bs, NULL); return -1; } diff --git a/src/io.c b/src/io.c index e4dfd33..2c92084 100644 --- a/src/io.c +++ b/src/io.c @@ -60,6 +60,9 @@ struct apk_istream *apk_istream_from_fd(int fd) { struct apk_fd_istream *fis; + if (fd < 0) + return NULL; + fis = malloc(sizeof(struct apk_fd_istream)); if (fis == NULL) return NULL; @@ -81,6 +84,8 @@ struct apk_istream *apk_istream_from_file(const char *file) if (fd < 0) return NULL; + fcntl(fd, F_SETFD, FD_CLOEXEC); + return apk_istream_from_fd(fd); } @@ -278,6 +283,9 @@ struct apk_bstream *apk_bstream_from_fd(int fd) { struct apk_bstream *bs; + if (fd < 0) + return NULL; + bs = apk_mmap_bstream_from_fd(fd); if (bs != NULL) return bs; @@ -285,6 +293,18 @@ struct apk_bstream *apk_bstream_from_fd(int fd) return apk_bstream_from_istream(apk_istream_from_fd(fd)); } +struct apk_bstream *apk_bstream_from_file(const char *file) +{ + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) + return NULL; + + fcntl(fd, F_SETFD, FD_CLOEXEC); + return apk_bstream_from_fd(fd); +} + apk_blob_t apk_blob_from_istream(struct apk_istream *is, size_t size) { void *ptr; @@ -338,7 +358,6 @@ int apk_file_get_info(const char *filename, struct apk_file_info *fi) { struct stat st; struct apk_bstream *bs; - int fd; if (stat(filename, &st) != 0) return -1; @@ -352,11 +371,7 @@ int apk_file_get_info(const char *filename, struct apk_file_info *fi) .device = st.st_dev, }; - fd = open(filename, O_RDONLY); - if (fd < 0) - return 0; - - bs = apk_bstream_from_fd(fd); + bs = apk_bstream_from_file(filename); if (bs != NULL) bs->close(bs, fi->csum); @@ -365,12 +380,6 @@ int apk_file_get_info(const char *filename, struct apk_file_info *fi) struct apk_istream *apk_istream_from_file_gz(const char *file) { - int fd; - - fd = open(file, O_RDONLY); - if (fd < 0) - return NULL; - - return apk_gunzip_bstream(apk_bstream_from_fd(fd)); + return apk_gunzip_bstream(apk_bstream_from_file(file)); } diff --git a/src/url.c b/src/url.c new file mode 100644 index 0000000..0999399 --- /dev/null +++ b/src/url.c @@ -0,0 +1,75 @@ +/* url.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008 Timo Teräs + * 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 +#include +#include +#include + +#include "apk_io.h" + +static const char *url_is_file(const char *url) +{ + if (strncmp(url, "file:", 5) == 0) + return &url[5]; + + if (strncmp(url, "http:", 5) != 0 && + strncmp(url, "https:", 6) != 0 && + strncmp(url, "ftp:", 4) != 0) + return url; + + return NULL; +} + +static int fork_wget(const char *url) +{ + pid_t pid; + int fds[2]; + + if (pipe(fds) < 0) + return -1; + + pid = fork(); + if (pid == -1) { + close(fds[0]); + close(fds[1]); + return -1; + } + + if (pid == 0) { + setsid(); + close(fds[0]); + dup2(open("/dev/null", O_WRONLY), STDERR_FILENO); + dup2(open("/dev/null", O_RDONLY), STDIN_FILENO); + dup2(fds[1], STDOUT_FILENO); + execlp("wget", "wget", "-O", "-", url, NULL); + exit(0); + } + + close(fds[1]); + return fds[0]; +} + +struct apk_istream *apk_istream_from_url(const char *url) +{ + if (url_is_file(url) != NULL) + return apk_istream_from_file(url_is_file(url)); + + return apk_istream_from_fd(fork_wget(url)); +} + +struct apk_bstream *apk_bstream_from_url(const char *url) +{ + if (url_is_file(url)) + return apk_bstream_from_file(url); + + return apk_bstream_from_fd(fork_wget(url)); +}