io: enhance istream/bstreams with pipe to forked child

* prunes the child pid to avoid zombies
 * handles the errors so e.g. file-not-found is reported properly
cute-signatures
Timo Teräs 2010-12-09 10:47:09 +02:00
parent c9690b0e7c
commit d92df52079
7 changed files with 84 additions and 22 deletions

View File

@ -18,7 +18,7 @@
#include "apk_defines.h" #include "apk_defines.h"
struct apk_blob { struct apk_blob {
unsigned int len; long len;
char *ptr; char *ptr;
}; };
typedef struct apk_blob apk_blob_t; typedef struct apk_blob apk_blob_t;
@ -56,6 +56,7 @@ static inline const EVP_MD *apk_checksum_default(void)
#define APK_BLOB_IS_NULL(blob) ((blob).ptr == NULL) #define APK_BLOB_IS_NULL(blob) ((blob).ptr == NULL)
#define APK_BLOB_NULL ((apk_blob_t){0, NULL}) #define APK_BLOB_NULL ((apk_blob_t){0, NULL})
#define APK_BLOB_ERROR(err) ((apk_blob_t){err, NULL})
#define APK_BLOB_BUF(buf) ((apk_blob_t){sizeof(buf), (char *)(buf)}) #define APK_BLOB_BUF(buf) ((apk_blob_t){sizeof(buf), (char *)(buf)})
#define APK_BLOB_CSUM(csum) ((apk_blob_t){(csum).type, (char *)(csum).data}) #define APK_BLOB_CSUM(csum) ((apk_blob_t){(csum).type, (char *)(csum).data})
#define APK_BLOB_STRUCT(s) ((apk_blob_t){sizeof(s), (char*)&(s)}) #define APK_BLOB_STRUCT(s) ((apk_blob_t){sizeof(s), (char*)&(s)})

View File

@ -73,7 +73,7 @@ static inline struct apk_istream *apk_bstream_gunzip(struct apk_bstream *bs)
struct apk_ostream *apk_ostream_gzip(struct apk_ostream *); struct apk_ostream *apk_ostream_gzip(struct apk_ostream *);
struct apk_ostream *apk_ostream_counter(off_t *); struct apk_ostream *apk_ostream_counter(off_t *);
struct apk_istream *apk_istream_from_fd(int fd); struct apk_istream *apk_istream_from_fd_pid(int fd, pid_t pid, int (*translate_status)(int));
struct apk_istream *apk_istream_from_file(int atfd, const char *file); struct apk_istream *apk_istream_from_file(int atfd, const char *file);
struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file); struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file);
struct apk_istream *apk_istream_from_url(const char *url); struct apk_istream *apk_istream_from_url(const char *url);
@ -82,12 +82,22 @@ size_t apk_istream_skip(struct apk_istream *istream, size_t size);
size_t apk_istream_splice(void *stream, int fd, size_t size, size_t apk_istream_splice(void *stream, int fd, size_t size,
apk_progress_cb cb, void *cb_ctx); apk_progress_cb cb, void *cb_ctx);
static inline struct apk_istream *apk_istream_from_fd(int fd)
{
return apk_istream_from_fd_pid(fd, 0, NULL);
}
struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream); 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_fd_pid(int fd, pid_t pid, int (*translate_status)(int));
struct apk_bstream *apk_bstream_from_file(int atfd, const char *file); struct apk_bstream *apk_bstream_from_file(int atfd, const char *file);
struct apk_bstream *apk_bstream_from_url(const char *url); struct apk_bstream *apk_bstream_from_url(const char *url);
struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to); struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const char *to);
static inline struct apk_bstream *apk_bstream_from_fd(int fd)
{
return apk_bstream_from_fd_pid(fd, 0, NULL);
}
struct apk_ostream *apk_ostream_to_fd(int fd); struct apk_ostream *apk_ostream_to_fd(int fd);
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, const char *tmpfile, mode_t mode); struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, const char *tmpfile, mode_t mode);
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode); struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode);

View File

@ -61,8 +61,8 @@ static ssize_t gzi_read(void *stream, void *ptr, size_t size)
gis->cbprev = blob.ptr; gis->cbprev = blob.ptr;
gis->zs.avail_in = blob.len; gis->zs.avail_in = blob.len;
gis->zs.next_in = (void *) gis->cbprev; gis->zs.next_in = (void *) gis->cbprev;
if (gis->zs.avail_in < 0) { if (blob.len < 0) {
gis->err = -EIO; gis->err = blob.len;
goto ret; goto ret;
} else if (gis->zs.avail_in == 0) { } else if (gis->zs.avail_in == 0) {
gis->err = 1; gis->err = 1;

View File

@ -15,6 +15,7 @@
#include <unistd.h> #include <unistd.h>
#include <malloc.h> #include <malloc.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/wait.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
@ -26,6 +27,8 @@
struct apk_fd_istream { struct apk_fd_istream {
struct apk_istream is; struct apk_istream is;
int fd; int fd;
pid_t pid;
int (*translate_status)(int status);
}; };
static ssize_t fdi_read(void *stream, void *ptr, size_t size) static ssize_t fdi_read(void *stream, void *ptr, size_t size)
@ -45,9 +48,15 @@ static ssize_t fdi_read(void *stream, void *ptr, size_t size)
if (r < 0) if (r < 0)
return -errno; return -errno;
if (r == 0) if (r == 0)
return i; break;
i += r; i += r;
} }
if (i == 0 && fis->pid != 0) {
int status;
if (waitpid(fis->pid, &status, 0) == fis->pid)
i = fis->translate_status(status);
fis->pid = 0;
}
return i; return i;
} }
@ -56,12 +65,15 @@ static void fdi_close(void *stream)
{ {
struct apk_fd_istream *fis = struct apk_fd_istream *fis =
container_of(stream, struct apk_fd_istream, is); container_of(stream, struct apk_fd_istream, is);
int status;
close(fis->fd); close(fis->fd);
if (fis->pid != 0)
waitpid(fis->pid, &status, 0);
free(fis); free(fis);
} }
struct apk_istream *apk_istream_from_fd(int fd) struct apk_istream *apk_istream_from_fd_pid(int fd, pid_t pid, int (*translate_status)(int))
{ {
struct apk_fd_istream *fis; struct apk_fd_istream *fis;
@ -78,6 +90,8 @@ struct apk_istream *apk_istream_from_fd(int fd)
.is.read = fdi_read, .is.read = fdi_read,
.is.close = fdi_close, .is.close = fdi_close,
.fd = fd, .fd = fd,
.pid = pid,
.translate_status = translate_status,
}; };
return &fis->is; return &fis->is;
@ -196,9 +210,9 @@ static apk_blob_t is_bs_read(void *stream, apk_blob_t token)
goto ret_all; goto ret_all;
} }
/* If we've exchausted earlier, it's end of stream */ /* If we've exchausted earlier, it's end of stream or error */
if (APK_BLOB_IS_NULL(isbs->left)) if (APK_BLOB_IS_NULL(isbs->left))
return APK_BLOB_NULL; return isbs->left;
/* We need more data */ /* We need more data */
if (isbs->left.len != 0) if (isbs->left.len != 0)
@ -213,6 +227,10 @@ static apk_blob_t is_bs_read(void *stream, apk_blob_t token)
if (isbs->left.len == 0) if (isbs->left.len == 0)
isbs->left = APK_BLOB_NULL; isbs->left = APK_BLOB_NULL;
goto ret_all; goto ret_all;
} else {
/* cache and return error */
isbs->left = ret = APK_BLOB_ERROR(size);
goto ret;
} }
if (!APK_BLOB_IS_NULL(token)) { if (!APK_BLOB_IS_NULL(token)) {
@ -294,7 +312,6 @@ static void mmap_close(void *stream, size_t *size)
if (size != NULL) if (size != NULL)
*size = mbs->size; *size = mbs->size;
munmap(mbs->ptr, mbs->size); munmap(mbs->ptr, mbs->size);
close(mbs->fd); close(mbs->fd);
free(mbs); free(mbs);
@ -332,18 +349,20 @@ static struct apk_bstream *apk_mmap_bstream_from_fd(int fd)
return &mbs->bs; return &mbs->bs;
} }
struct apk_bstream *apk_bstream_from_fd(int fd) struct apk_bstream *apk_bstream_from_fd_pid(int fd, pid_t pid, int (*translate_status)(int))
{ {
struct apk_bstream *bs; struct apk_bstream *bs;
if (fd < 0) if (fd < 0)
return NULL; return NULL;
if (pid == 0) {
bs = apk_mmap_bstream_from_fd(fd); bs = apk_mmap_bstream_from_fd(fd);
if (bs != NULL) if (bs != NULL)
return bs; return bs;
}
return apk_bstream_from_istream(apk_istream_from_fd(fd)); return apk_bstream_from_istream(apk_istream_from_fd_pid(fd, pid, translate_status));
} }
struct apk_bstream *apk_bstream_from_file(int atfd, const char *file) struct apk_bstream *apk_bstream_from_file(int atfd, const char *file)

View File

@ -26,7 +26,7 @@ int apk_print_indented(struct apk_indent *i, apk_blob_t blob)
i->x = i->indent; i->x = i->indent;
printf("\n%*s", i->indent - 1, ""); printf("\n%*s", i->indent - 1, "");
} }
i->x += printf(" %.*s", blob.len, blob.ptr); i->x += printf(" %.*s", (int) blob.len, blob.ptr);
return 0; return 0;
} }

View File

@ -31,7 +31,26 @@ const char *apk_url_local_file(const char *url)
return NULL; return NULL;
} }
static int fork_wget(const char *url) static int translate_wget(int status)
{
if (!WIFEXITED(status))
return -EFAULT;
switch (WEXITSTATUS(status)) {
case 0:
return 0;
case 3:
return -EIO;
case 4:
return -ECONNABORTED;
case 8:
return -ENOENT;
default:
return -EFAULT;
}
}
static int fork_wget(const char *url, pid_t *ppid)
{ {
pid_t pid; pid_t pid;
int fds[2]; int fds[2];
@ -56,15 +75,23 @@ static int fork_wget(const char *url)
} }
close(fds[1]); close(fds[1]);
if (ppid != NULL)
*ppid = pid;
return fds[0]; return fds[0];
} }
struct apk_istream *apk_istream_from_url(const char *url) struct apk_istream *apk_istream_from_url(const char *url)
{ {
pid_t pid;
int fd;
if (apk_url_local_file(url) != NULL) if (apk_url_local_file(url) != NULL)
return apk_istream_from_file(AT_FDCWD, apk_url_local_file(url)); return apk_istream_from_file(AT_FDCWD, apk_url_local_file(url));
return apk_istream_from_fd(fork_wget(url)); fd = fork_wget(url, &pid);
return apk_istream_from_fd_pid(fd, pid, translate_wget);
} }
struct apk_istream *apk_istream_from_url_gz(const char *file) struct apk_istream *apk_istream_from_url_gz(const char *file)
@ -74,10 +101,14 @@ struct apk_istream *apk_istream_from_url_gz(const char *file)
struct apk_bstream *apk_bstream_from_url(const char *url) struct apk_bstream *apk_bstream_from_url(const char *url)
{ {
pid_t pid;
int fd;
if (apk_url_local_file(url)) if (apk_url_local_file(url))
return apk_bstream_from_file(AT_FDCWD, url); return apk_bstream_from_file(AT_FDCWD, url);
return apk_bstream_from_fd(fork_wget(url)); fd = fork_wget(url, &pid);
return apk_bstream_from_fd_pid(fd, pid, translate_wget);
} }
int apk_url_download(const char *url, int atfd, const char *file) int apk_url_download(const char *url, int atfd, const char *file)
@ -102,9 +133,10 @@ int apk_url_download(const char *url, int atfd, const char *file)
} }
waitpid(pid, &status, 0); waitpid(pid, &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { status = translate_wget(status);
if (status != 0) {
unlinkat(atfd, file, 0); unlinkat(atfd, file, 0);
return -1; return status;
} }
return 0; return 0;

View File

@ -33,7 +33,7 @@ static int ver_indexes(struct apk_database *db, int argc, char **argv)
continue; continue;
printf("%.*s [%s]\n", printf("%.*s [%s]\n",
repo->description.len, (int) repo->description.len,
repo->description.ptr, repo->description.ptr,
db->repos[i].url); db->repos[i].url);
} }