#include <sys/wait.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
static const char *const comps[COMP__MAX] = {
"netproc",
"keyproc",
"certproc",
"acctproc",
"challengeproc",
"fileproc",
"dnsproc",
"revokeproc",
};
static const char *const comms[COMM__MAX] = {
"req",
"thumbprint",
"cert",
"payload",
"nonce",
"token",
"challenge-op",
"challenge-ack",
"account",
"acctpro-status",
"csr",
"csr-op",
"issuer",
"chain",
"chain-op",
"dns",
"dnsq",
"dns-address",
"dns-family",
"dns-length",
"keyproc-status",
"revoke-op",
"revoke-check",
"revoke-response",
};
long
readop(int fd, enum comm comm)
{
ssize_t ssz;
long op;
ssz = read(fd, &op, sizeof(long));
if (ssz == -1) {
warn("read: %s", comms[comm]);
return LONG_MAX;
} else if (ssz && ssz != sizeof(long)) {
warnx("short read: %s", comms[comm]);
return LONG_MAX;
} else if (ssz == 0)
return 0;
return op;
}
char *
readstr(int fd, enum comm comm)
{
size_t sz;
return readbuf(fd, comm, &sz);
}
char *
readbuf(int fd, enum comm comm, size_t *sz)
{
ssize_t ssz;
size_t rsz, lsz;
char *p = NULL;
if ((ssz = read(fd, sz, sizeof(size_t))) == -1) {
warn("read: %s length", comms[comm]);
return NULL;
} else if ((size_t)ssz != sizeof(size_t)) {
warnx("short read: %s length", comms[comm]);
return NULL;
} else if (*sz > SIZE_MAX - 1) {
warnx("integer overflow");
return NULL;
} else if ((p = calloc(1, *sz + 1)) == NULL) {
warn("malloc");
return NULL;
}
rsz = 0;
lsz = *sz;
while (lsz) {
if ((ssz = read(fd, p + rsz, lsz)) == -1) {
warn("read: %s", comms[comm]);
break;
} else if (ssz > 0) {
assert((size_t)ssz <= lsz);
rsz += (size_t)ssz;
lsz -= (size_t)ssz;
}
}
if (lsz) {
warnx("couldn't read buffer: %s", comms[comm]);
free(p);
return NULL;
}
return p;
}
int
writeop(int fd, enum comm comm, long op)
{
ssize_t ssz;
int er;
if ((ssz = write(fd, &op, sizeof(long))) == -1) {
if ((er = errno) != EPIPE)
warn("write: %s", comms[comm]);
return er == EPIPE ? 0 : -1;
}
if ((size_t)ssz != sizeof(long)) {
warnx("short write: %s", comms[comm]);
return -1;
}
return 1;
}
int
writebuf(int fd, enum comm comm, const void *v, size_t sz)
{
ssize_t ssz;
int er, rc = -1;
if ((ssz = write(fd, &sz, sizeof(size_t))) == -1) {
if ((er = errno) != EPIPE)
warn("write: %s length", comms[comm]);
return er == EPIPE ? 0 : -1;
}
if ((size_t)ssz != sizeof(size_t))
warnx("short write: %s length", comms[comm]);
else if ((ssz = write(fd, v, sz)) == -1) {
if (errno == EPIPE)
rc = 0;
else
warn("write: %s", comms[comm]);
} else if (sz != (size_t)ssz)
warnx("short write: %s", comms[comm]);
else
rc = 1;
return rc;
}
int
writestr(int fd, enum comm comm, const char *v)
{
return writebuf(fd, comm, v, strlen(v));
}
int
checkexit(pid_t pid, enum comp comp)
{
int c, cc;
const char *cp;
if (waitpid(pid, &c, 0) == -1) {
warn("waitpid");
return 0;
} else if (!WIFEXITED(c) && WIFSIGNALED(c)) {
cp = strsignal(WTERMSIG(c));
warnx("signal: %s(%u): %s", comps[comp], pid, cp);
return 0;
} else if (!WIFEXITED(c)) {
warnx("did not exit: %s(%u)", comps[comp], pid);
return 0;
} else if (WEXITSTATUS(c) != EXIT_SUCCESS) {
cc = WEXITSTATUS(c);
dodbg("bad exit: %s(%u): %d", comps[comp], pid, cc);
return 0;
}
return 1;
}
int
checkexit_ext(int *rc, pid_t pid, enum comp comp)
{
int c;
const char *cp;
*rc = EXIT_FAILURE;
if (waitpid(pid, &c, 0) == -1) {
warn("waitpid");
return 0;
}
if (!WIFEXITED(c) && WIFSIGNALED(c)) {
cp = strsignal(WTERMSIG(c));
warnx("signal: %s(%u): %s", comps[comp], pid, cp);
return 0;
} else if (!WIFEXITED(c)) {
warnx("did not exit: %s(%u)", comps[comp], pid);
return 0;
}
if ((*rc = WEXITSTATUS(c)) != EXIT_SUCCESS && *rc != 2) {
dodbg("bad exit: %s(%u): %d", comps[comp], pid, *rc);
return 0;
}
return 1;
}